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 * The default toString style. Using the {@code Person} example from {@link ToStringBuilder}, the output would look like this:
501 *
502 * <pre>
503 * Person@182f0db[name=John Doe,age=33,smoker=false]
504 * </pre>
505 */
506 public static final ToStringStyle DEFAULT_STYLE = new DefaultToStringStyle();
507 /**
508 * The multi line toString style. Using the {@code Person} example from {@link ToStringBuilder}, the output would look like this:
509 *
510 * <pre>
511 * Person@182f0db[
512 * name=John Doe
513 * age=33
514 * smoker=false
515 * ]
516 * </pre>
517 */
518 public static final ToStringStyle MULTI_LINE_STYLE = new MultiLineToStringStyle();
519 /**
520 * The no field names toString style. Using the {@code Person} example from {@link ToStringBuilder}, the output would look like this:
521 *
522 * <pre>
523 * Person@182f0db[John Doe,33,false]
524 * </pre>
525 */
526 public static final ToStringStyle NO_FIELD_NAMES_STYLE = new NoFieldNameToStringStyle();
527 /**
528 * The short prefix toString style. Using the {@code Person} example from {@link ToStringBuilder}, the output would look like this:
529 *
530 * <pre>
531 * Person[name=John Doe,age=33,smoker=false]
532 * </pre>
533 *
534 * @since 2.1
535 */
536 public static final ToStringStyle SHORT_PREFIX_STYLE = new ShortPrefixToStringStyle();
537 /**
538 * The simple toString style. Using the {@code Person} example from {@link ToStringBuilder}, the output would look like this:
539 *
540 * <pre>
541 * John Doe,33,false
542 * </pre>
543 */
544 public static final ToStringStyle SIMPLE_STYLE = new SimpleToStringStyle();
545 /**
546 * The no class name toString style. Using the {@code Person} example from {@link ToStringBuilder}, the output would look like this:
547 *
548 * <pre>
549 * [name=John Doe,age=33,smoker=false]
550 * </pre>
551 *
552 * @since 3.4
553 */
554 public static final ToStringStyle NO_CLASS_NAME_STYLE = new NoClassNameToStringStyle();
555 /**
556 * The JSON toString style. Using the {@code Person} example from {@link ToStringBuilder}, the output would look like this:
557 *
558 * <pre>
559 * {"name": "John Doe", "age": 33, "smoker": true}
560 * </pre>
561 *
562 * <strong>Note:</strong> Since field names are mandatory in JSON, this ToStringStyle will throw an {@link UnsupportedOperationException} if no field name
563 * is passed in while appending. Furthermore This ToStringStyle will only generate valid JSON if referenced objects also produce JSON when calling
564 * {@code toString()} on them.
565 *
566 * @since 3.4
567 * @see <a href="https://www.json.org/">json.org</a>
568 */
569 public static final ToStringStyle JSON_STYLE = new JsonToStringStyle();
570 /**
571 * A registry of objects used by {@code reflectionToString} methods to detect cyclical object references and avoid infinite loops.
572 */
573 private static final ThreadLocal<WeakHashMap<Object, Object>> REGISTRY = ThreadLocal.withInitial(WeakHashMap::new);
574 /*
575 * Note that objects of this class are generally shared between threads, so an instance variable would not be suitable here.
576 *
577 * In normal use the registry should always be left empty, because the caller should call toString() which will clean up.
578 *
579 * See LANG-792
580 */
581
582 /**
583 * Gets the registry of objects being traversed by the {@code reflectionToString} methods in the current thread.
584 *
585 * @return Set the registry of objects being traversed.
586 */
587 public static Map<Object, Object> getRegistry() {
588 return REGISTRY.get();
589 }
590
591 /**
592 * Tests whether the registry contains the given object. Used by the reflection methods to avoid infinite loops.
593 *
594 * @param value The object to lookup in the registry.
595 * @return boolean {@code true} if the registry contains the given object.
596 */
597 static boolean isRegistered(final Object value) {
598 return getRegistry().containsKey(value);
599 }
600
601 /**
602 * Registers the given object. Used by the reflection methods to avoid infinite loops.
603 *
604 * @param value The object to register.
605 */
606 static void register(final Object value) {
607 if (value != null) {
608 getRegistry().put(value, null);
609 }
610 }
611
612 /**
613 * Unregisters the given object.
614 *
615 * <p>
616 * Used by the reflection methods to avoid infinite loops.
617 * </p>
618 *
619 * @param value The object to unregister.
620 */
621 static void unregister(final Object value) {
622 if (value != null) {
623 final Map<Object, Object> m = getRegistry();
624 m.remove(value);
625 if (m.isEmpty()) {
626 REGISTRY.remove();
627 }
628 }
629 }
630
631 /**
632 * Whether to use the field names, the default is {@code true}.
633 */
634 private boolean useFieldNames = true;
635 /**
636 * Whether to use the class name, the default is {@code true}.
637 */
638 private boolean useClassName = true;
639 /**
640 * Whether to use short class names, the default is {@code false}.
641 */
642 private boolean useShortClassName;
643 /**
644 * Whether to use the identity hash code, the default is {@code true}.
645 */
646 private boolean useIdentityHashCode = true;
647 /**
648 * The content start {@code '['}.
649 */
650 private String contentStart = "[";
651 /**
652 * The content end {@code ']'}.
653 */
654 private String contentEnd = "]";
655 /**
656 * The field name value separator {@code '='}.
657 */
658 private String fieldNameValueSeparator = "=";
659 /**
660 * Whether the field separator should be added before any other fields.
661 */
662 private boolean fieldSeparatorAtStart;
663 /**
664 * Whether the field separator should be added after any other fields.
665 */
666 private boolean fieldSeparatorAtEnd;
667 /**
668 * The field separator {@code ','}.
669 */
670 private String fieldSeparator = ",";
671 /**
672 * The array start <code>'{'</code>.
673 */
674 private String arrayStart = "{";
675 /**
676 * The array separator {@code ','}.
677 */
678 private String arraySeparator = ",";
679 /**
680 * The detail for array content.
681 */
682 private boolean arrayContentDetail = true;
683 /**
684 * The array end {@code '}'}.
685 */
686 private String arrayEnd = "}";
687 /**
688 * The value to use when fullDetail is {@code null}, the default value is {@code true}.
689 */
690 private boolean defaultFullDetail = true;
691 /**
692 * The {@code null} text {@code "<null>"}.
693 */
694 private String nullText = "<null>";
695 /**
696 * The summary size text start {@code "<size="}.
697 */
698 private String sizeStartText = "<size=";
699 /**
700 * The summary size text start {@code ">"}.
701 */
702 private String sizeEndText = ">";
703 /**
704 * The summary object text start {@code "<"}.
705 */
706 private String summaryObjectStartText = "<";
707 /**
708 * The summary object text start {@code ">"}.
709 */
710 private String summaryObjectEndText = ">";
711
712 /**
713 * Constructs a new instance.
714 */
715 protected ToStringStyle() {
716 }
717
718 /**
719 * Appends to the {@code toString} a {@code boolean} value.
720 *
721 * @param buffer the {@link StringBuffer} to populate.
722 * @param fieldName the field name.
723 * @param value the value to add to the {@code toString}.
724 */
725 public void append(final StringBuffer buffer, final String fieldName, final boolean value) {
726 appendFieldStart(buffer, fieldName);
727 appendDetail(buffer, fieldName, value);
728 appendFieldEnd(buffer, fieldName);
729 }
730
731 /**
732 * Appends to the {@code toString} a {@code boolean} array.
733 *
734 * @param buffer the {@link StringBuffer} to populate.
735 * @param fieldName the field name.
736 * @param array the array to add to the toString.
737 * @param fullDetail {@code true} for detail, {@code false} for summary info, {@code null} for style decides.
738 */
739 public void append(final StringBuffer buffer, final String fieldName, final boolean[] array, final Boolean fullDetail) {
740 appendFieldStart(buffer, fieldName);
741 if (array == null) {
742 appendNullText(buffer, fieldName);
743 } else if (isFullDetail(fullDetail)) {
744 appendDetail(buffer, fieldName, array);
745 } else {
746 appendSummary(buffer, fieldName, array);
747 }
748 appendFieldEnd(buffer, fieldName);
749 }
750
751 /**
752 * Appends to the {@code toString} a {@code byte} value.
753 *
754 * @param buffer the {@link StringBuffer} to populate.
755 * @param fieldName the field name.
756 * @param value the value to add to the {@code toString}.
757 */
758 public void append(final StringBuffer buffer, final String fieldName, final byte value) {
759 appendFieldStart(buffer, fieldName);
760 appendDetail(buffer, fieldName, value);
761 appendFieldEnd(buffer, fieldName);
762 }
763
764 /**
765 * Appends to the {@code toString} a {@code byte} array.
766 *
767 * @param buffer the {@link StringBuffer} to populate.
768 * @param fieldName the field name.
769 * @param array the array to add to the {@code toString}.
770 * @param fullDetail {@code true} for detail, {@code false} for summary info, {@code null} for style decides.
771 */
772 public void append(final StringBuffer buffer, final String fieldName, final byte[] array, final Boolean fullDetail) {
773 appendFieldStart(buffer, fieldName);
774 if (array == null) {
775 appendNullText(buffer, fieldName);
776 } else if (isFullDetail(fullDetail)) {
777 appendDetail(buffer, fieldName, array);
778 } else {
779 appendSummary(buffer, fieldName, array);
780 }
781 appendFieldEnd(buffer, fieldName);
782 }
783
784 /**
785 * Appends to the {@code toString} a {@code char} value.
786 *
787 * @param buffer the {@link StringBuffer} to populate.
788 * @param fieldName the field name.
789 * @param value the value to add to the {@code toString}.
790 */
791 public void append(final StringBuffer buffer, final String fieldName, final char value) {
792 appendFieldStart(buffer, fieldName);
793 appendDetail(buffer, fieldName, value);
794 appendFieldEnd(buffer, fieldName);
795 }
796
797 /**
798 * Appends to the {@code toString} a {@code char} array.
799 *
800 * @param buffer the {@link StringBuffer} to populate.
801 * @param fieldName the field name.
802 * @param array the array to add to the {@code toString}.
803 * @param fullDetail {@code true} for detail, {@code false} for summary info, {@code null} for style decides.
804 */
805 public void append(final StringBuffer buffer, final String fieldName, final char[] array, final Boolean fullDetail) {
806 appendFieldStart(buffer, fieldName);
807 if (array == null) {
808 appendNullText(buffer, fieldName);
809 } else if (isFullDetail(fullDetail)) {
810 appendDetail(buffer, fieldName, array);
811 } else {
812 appendSummary(buffer, fieldName, array);
813 }
814 appendFieldEnd(buffer, fieldName);
815 }
816
817 /**
818 * Appends to the {@code toString} a {@code double} value.
819 *
820 * @param buffer the {@link StringBuffer} to populate.
821 * @param fieldName the field name.
822 * @param value the value to add to the {@code toString}.
823 */
824 public void append(final StringBuffer buffer, final String fieldName, final double value) {
825 appendFieldStart(buffer, fieldName);
826 appendDetail(buffer, fieldName, value);
827 appendFieldEnd(buffer, fieldName);
828 }
829
830 /**
831 * Appends to the {@code toString} a {@code double} array.
832 *
833 * @param buffer the {@link StringBuffer} to populate.
834 * @param fieldName the field name.
835 * @param array the array to add to the toString.
836 * @param fullDetail {@code true} for detail, {@code false} for summary info, {@code null} for style decides.
837 */
838 public void append(final StringBuffer buffer, final String fieldName, final double[] array, final Boolean fullDetail) {
839 appendFieldStart(buffer, fieldName);
840 if (array == null) {
841 appendNullText(buffer, fieldName);
842 } else if (isFullDetail(fullDetail)) {
843 appendDetail(buffer, fieldName, array);
844 } else {
845 appendSummary(buffer, fieldName, array);
846 }
847 appendFieldEnd(buffer, fieldName);
848 }
849
850 /**
851 * Appends to the {@code toString} a {@code float} value.
852 *
853 * @param buffer the {@link StringBuffer} to populate.
854 * @param fieldName the field name.
855 * @param value the value to add to the {@code toString}.
856 */
857 public void append(final StringBuffer buffer, final String fieldName, final float value) {
858 appendFieldStart(buffer, fieldName);
859 appendDetail(buffer, fieldName, value);
860 appendFieldEnd(buffer, fieldName);
861 }
862
863 /**
864 * Appends to the {@code toString} a {@code float} array.
865 *
866 * @param buffer the {@link StringBuffer} to populate.
867 * @param fieldName the field name.
868 * @param array the array to add to the toString.
869 * @param fullDetail {@code true} for detail, {@code false} for summary info, {@code null} for style decides.
870 */
871 public void append(final StringBuffer buffer, final String fieldName, final float[] array, final Boolean fullDetail) {
872 appendFieldStart(buffer, fieldName);
873 if (array == null) {
874 appendNullText(buffer, fieldName);
875 } else if (isFullDetail(fullDetail)) {
876 appendDetail(buffer, fieldName, array);
877 } else {
878 appendSummary(buffer, fieldName, array);
879 }
880 appendFieldEnd(buffer, fieldName);
881 }
882
883 /**
884 * Appends to the {@code toString} an {@code int} value.
885 *
886 * @param buffer the {@link StringBuffer} to populate.
887 * @param fieldName the field name.
888 * @param value the value to add to the {@code toString}.
889 */
890 public void append(final StringBuffer buffer, final String fieldName, final int value) {
891 appendFieldStart(buffer, fieldName);
892 appendDetail(buffer, fieldName, value);
893 appendFieldEnd(buffer, fieldName);
894 }
895
896 /**
897 * Appends to the {@code toString} an {@code int} array.
898 *
899 * @param buffer the {@link StringBuffer} to populate.
900 * @param fieldName the field name.
901 * @param array the array to add to the {@code toString}.
902 * @param fullDetail {@code true} for detail, {@code false} for summary info, {@code null} for style decides.
903 */
904 public void append(final StringBuffer buffer, final String fieldName, final int[] array, final Boolean fullDetail) {
905 appendFieldStart(buffer, fieldName);
906 if (array == null) {
907 appendNullText(buffer, fieldName);
908 } else if (isFullDetail(fullDetail)) {
909 appendDetail(buffer, fieldName, array);
910 } else {
911 appendSummary(buffer, fieldName, array);
912 }
913 appendFieldEnd(buffer, fieldName);
914 }
915
916 /**
917 * Appends to the {@code toString} a {@code long} value.
918 *
919 * @param buffer the {@link StringBuffer} to populate.
920 * @param fieldName the field name.
921 * @param value the value to add to the {@code toString}.
922 */
923 public void append(final StringBuffer buffer, final String fieldName, final long value) {
924 appendFieldStart(buffer, fieldName);
925 appendDetail(buffer, fieldName, value);
926 appendFieldEnd(buffer, fieldName);
927 }
928
929 /**
930 * Appends to the {@code toString} a {@code long} array.
931 *
932 * @param buffer the {@link StringBuffer} to populate.
933 * @param fieldName the field name.
934 * @param array the array to add to the {@code toString}.
935 * @param fullDetail {@code true} for detail, {@code false} for summary info, {@code null} for style decides.
936 */
937 public void append(final StringBuffer buffer, final String fieldName, final long[] array, final Boolean fullDetail) {
938 appendFieldStart(buffer, fieldName);
939 if (array == null) {
940 appendNullText(buffer, fieldName);
941 } else if (isFullDetail(fullDetail)) {
942 appendDetail(buffer, fieldName, array);
943 } else {
944 appendSummary(buffer, fieldName, array);
945 }
946 appendFieldEnd(buffer, fieldName);
947 }
948
949 /**
950 * Appends to the {@code toString} an {@link Object} value, printing the full {@code toString} of the {@link Object} passed in.
951 *
952 * @param buffer the {@link StringBuffer} to populate.
953 * @param fieldName the field name.
954 * @param value the value to add to the {@code toString}.
955 * @param fullDetail {@code true} for detail, {@code false} for summary info, {@code null} for style decides.
956 */
957 public void append(final StringBuffer buffer, final String fieldName, final Object value, final Boolean fullDetail) {
958 appendFieldStart(buffer, fieldName);
959 if (value == null) {
960 appendNullText(buffer, fieldName);
961 } else {
962 appendInternal(buffer, fieldName, value, isFullDetail(fullDetail));
963 }
964 appendFieldEnd(buffer, fieldName);
965 }
966
967 /**
968 * Appends to the {@code toString} an {@link Object} array.
969 *
970 * @param buffer the {@link StringBuffer} to populate.
971 * @param fieldName the field name.
972 * @param array the array to add to the toString.
973 * @param fullDetail {@code true} for detail, {@code false} for summary info, {@code null} for style decides.
974 */
975 public void append(final StringBuffer buffer, final String fieldName, final Object[] array, final Boolean fullDetail) {
976 appendFieldStart(buffer, fieldName);
977 if (array == null) {
978 appendNullText(buffer, fieldName);
979 } else if (isFullDetail(fullDetail)) {
980 appendDetail(buffer, fieldName, array);
981 } else {
982 appendSummary(buffer, fieldName, array);
983 }
984 appendFieldEnd(buffer, fieldName);
985 }
986
987 /**
988 * Appends to the {@code toString} a {@code short} value.
989 *
990 * @param buffer the {@link StringBuffer} to populate.
991 * @param fieldName the field name.
992 * @param value the value to add to the {@code toString}.
993 */
994 public void append(final StringBuffer buffer, final String fieldName, final short value) {
995 appendFieldStart(buffer, fieldName);
996 appendDetail(buffer, fieldName, value);
997 appendFieldEnd(buffer, fieldName);
998 }
999
1000 /**
1001 * Appends to the {@code toString} a {@code short} array.
1002 *
1003 * @param buffer the {@link StringBuffer} to populate.
1004 * @param fieldName the field name.
1005 * @param array the array to add to the {@code toString}.
1006 * @param fullDetail {@code true} for detail, {@code false} for summary info, {@code null} for style decides.
1007 */
1008 public void append(final StringBuffer buffer, final String fieldName, final short[] array, final Boolean fullDetail) {
1009 appendFieldStart(buffer, fieldName);
1010 if (array == null) {
1011 appendNullText(buffer, fieldName);
1012 } else if (isFullDetail(fullDetail)) {
1013 appendDetail(buffer, fieldName, array);
1014 } else {
1015 appendSummary(buffer, fieldName, array);
1016 }
1017 appendFieldEnd(buffer, fieldName);
1018 }
1019
1020 /**
1021 * Appends to the {@code toString} the class name.
1022 *
1023 * @param buffer the {@link StringBuffer} to populate.
1024 * @param object the {@link Object} whose name to output.
1025 */
1026 protected void appendClassName(final StringBuffer buffer, final Object object) {
1027 if (isUseClassName() && object != null) {
1028 register(object);
1029 if (isUseShortClassName()) {
1030 buffer.append(getShortClassName(object.getClass()));
1031 } else {
1032 buffer.append(object.getClass().getName());
1033 }
1034 }
1035 }
1036
1037 /**
1038 * Appends to the {@code toString} the content end.
1039 *
1040 * @param buffer the {@link StringBuffer} to populate.
1041 */
1042 protected void appendContentEnd(final StringBuffer buffer) {
1043 buffer.append(getContentEnd());
1044 }
1045
1046 /**
1047 * Appends to the {@code toString} the content start.
1048 *
1049 * @param buffer the {@link StringBuffer} to populate.
1050 */
1051 protected void appendContentStart(final StringBuffer buffer) {
1052 buffer.append(getContentStart());
1053 }
1054
1055 /**
1056 * Appends to the {@code toString} an {@link Object} value that has been detected to participate in a cycle. This implementation will print the standard
1057 * string value of the value.
1058 *
1059 * @param buffer the {@link StringBuffer} to populate.
1060 * @param fieldName the field name, typically not used as already appended
1061 * @param value the value to add to the {@code toString}, not {@code null}.
1062 * @since 2.2
1063 */
1064 protected void appendCyclicObject(final StringBuffer buffer, final String fieldName, final Object value) {
1065 ObjectUtils.identityToString(buffer, value);
1066 }
1067
1068 /**
1069 * Appends to the {@code toString} a {@code boolean} value.
1070 *
1071 * @param buffer the {@link StringBuffer} to populate.
1072 * @param fieldName the field name, typically not used as already appended.
1073 * @param value the value to add to the {@code toString}.
1074 */
1075 protected void appendDetail(final StringBuffer buffer, final String fieldName, final boolean value) {
1076 buffer.append(value);
1077 }
1078
1079 /**
1080 * Appends to the {@code toString} the detail of a {@code boolean} array.
1081 *
1082 * @param buffer the {@link StringBuffer} to populate.
1083 * @param fieldName the field name, typically not used as already appended.
1084 * @param array the array to add to the {@code toString}, not {@code null}.
1085 */
1086 protected void appendDetail(final StringBuffer buffer, final String fieldName, final boolean[] array) {
1087 buffer.append(getArrayStart());
1088 for (int i = 0; i < array.length; i++) {
1089 if (i > 0) {
1090 buffer.append(getArraySeparator());
1091 }
1092 appendDetail(buffer, fieldName, array[i]);
1093 }
1094 buffer.append(getArrayEnd());
1095 }
1096
1097 /**
1098 * Appends to the {@code toString} a {@code byte} value.
1099 *
1100 * @param buffer the {@link StringBuffer} to populate.
1101 * @param fieldName the field name, typically not used as already appended.
1102 * @param value the value to add to the {@code toString}.
1103 */
1104 protected void appendDetail(final StringBuffer buffer, final String fieldName, final byte value) {
1105 buffer.append(value);
1106 }
1107
1108 /**
1109 * Appends to the {@code toString} the detail of a {@code byte} array.
1110 *
1111 * @param buffer the {@link StringBuffer} to populate.
1112 * @param fieldName the field name, typically not used as already appended.
1113 * @param array the array to add to the {@code toString}, not {@code null}.
1114 */
1115 protected void appendDetail(final StringBuffer buffer, final String fieldName, final byte[] array) {
1116 buffer.append(getArrayStart());
1117 for (int i = 0; i < array.length; i++) {
1118 if (i > 0) {
1119 buffer.append(getArraySeparator());
1120 }
1121 appendDetail(buffer, fieldName, array[i]);
1122 }
1123 buffer.append(getArrayEnd());
1124 }
1125
1126 /**
1127 * Appends to the {@code toString} a {@code char} value.
1128 *
1129 * @param buffer the {@link StringBuffer} to populate.
1130 * @param fieldName the field name, typically not used as already appended.
1131 * @param value the value to add to the {@code toString}.
1132 */
1133 protected void appendDetail(final StringBuffer buffer, final String fieldName, final char value) {
1134 buffer.append(value);
1135 }
1136
1137 /**
1138 * Appends to the {@code toString} the detail of a {@code char} array.
1139 *
1140 * @param buffer the {@link StringBuffer} to populate.
1141 * @param fieldName the field name, typically not used as already appended.
1142 * @param array the array to add to the {@code toString}, not {@code null}.
1143 */
1144 protected void appendDetail(final StringBuffer buffer, final String fieldName, final char[] array) {
1145 buffer.append(getArrayStart());
1146 for (int i = 0; i < array.length; i++) {
1147 if (i > 0) {
1148 buffer.append(getArraySeparator());
1149 }
1150 appendDetail(buffer, fieldName, array[i]);
1151 }
1152 buffer.append(getArrayEnd());
1153 }
1154
1155 /**
1156 * Appends to the {@code toString} a {@link Collection}.
1157 *
1158 * @param buffer the {@link StringBuffer} to populate.
1159 * @param fieldName the field name, typically not used as already appended.
1160 * @param coll the {@link Collection} to add to the {@code toString}, not {@code null}.
1161 */
1162 protected void appendDetail(final StringBuffer buffer, final String fieldName, final Collection<?> coll) {
1163 buffer.append(coll);
1164 }
1165
1166 /**
1167 * Appends to the {@code toString} a {@code double} value.
1168 *
1169 * @param buffer the {@link StringBuffer} to populate.
1170 * @param fieldName the field name, typically not used as already appended.
1171 * @param value the value to add to the {@code toString}.
1172 */
1173 protected void appendDetail(final StringBuffer buffer, final String fieldName, final double value) {
1174 buffer.append(value);
1175 }
1176
1177 /**
1178 * Appends to the {@code toString} the detail of a {@code double} array.
1179 *
1180 * @param buffer the {@link StringBuffer} to populate.
1181 * @param fieldName the field name, typically not used as already appended
1182 * @param array the array to add to the {@code toString}, not {@code null}.
1183 */
1184 protected void appendDetail(final StringBuffer buffer, final String fieldName, final double[] array) {
1185 buffer.append(getArrayStart());
1186 for (int i = 0; i < array.length; i++) {
1187 if (i > 0) {
1188 buffer.append(getArraySeparator());
1189 }
1190 appendDetail(buffer, fieldName, array[i]);
1191 }
1192 buffer.append(getArrayEnd());
1193 }
1194
1195 /**
1196 * Appends to the {@code toString} a {@code float} value.
1197 *
1198 * @param buffer the {@link StringBuffer} to populate.
1199 * @param fieldName the field name, typically not used as already appended.
1200 * @param value the value to add to the {@code toString}.
1201 */
1202 protected void appendDetail(final StringBuffer buffer, final String fieldName, final float value) {
1203 buffer.append(value);
1204 }
1205
1206 /**
1207 * Appends to the {@code toString} the detail of a {@code float} array.
1208 *
1209 * @param buffer the {@link StringBuffer} to populate.
1210 * @param fieldName the field name, typically not used as already appended.
1211 * @param array the array to add to the {@code toString}, not {@code null}.
1212 */
1213 protected void appendDetail(final StringBuffer buffer, final String fieldName, final float[] array) {
1214 buffer.append(getArrayStart());
1215 for (int i = 0; i < array.length; i++) {
1216 if (i > 0) {
1217 buffer.append(getArraySeparator());
1218 }
1219 appendDetail(buffer, fieldName, array[i]);
1220 }
1221 buffer.append(getArrayEnd());
1222 }
1223
1224 /**
1225 * Appends to the {@code toString} an {@code int} value.
1226 *
1227 * @param buffer the {@link StringBuffer} to populate.
1228 * @param fieldName the field name, typically not used as already appended.
1229 * @param value the value to add to the {@code toString}.
1230 */
1231 protected void appendDetail(final StringBuffer buffer, final String fieldName, final int value) {
1232 buffer.append(value);
1233 }
1234
1235 /**
1236 * Appends to the {@code toString} the detail of an {@link Object} array item.
1237 *
1238 * @param buffer the {@link StringBuffer} to populate.
1239 * @param fieldName the field name, typically not used as already appended.
1240 * @param i the array item index to add.
1241 * @param item the array item to add.
1242 * @since 3.11
1243 */
1244 protected void appendDetail(final StringBuffer buffer, final String fieldName, final int i, final Object item) {
1245 if (i > 0) {
1246 buffer.append(getArraySeparator());
1247 }
1248 if (item == null) {
1249 appendNullText(buffer, fieldName);
1250 } else {
1251 appendInternal(buffer, fieldName, item, isArrayContentDetail());
1252 }
1253 }
1254
1255 /**
1256 * Appends to the {@code toString} the detail of an {@code int} array.
1257 *
1258 * @param buffer the {@link StringBuffer} to populate.
1259 * @param fieldName the field name, typically not used as already appended.
1260 * @param array the array to add to the {@code toString}, not {@code null}.
1261 */
1262 protected void appendDetail(final StringBuffer buffer, final String fieldName, final int[] array) {
1263 buffer.append(getArrayStart());
1264 for (int i = 0; i < array.length; i++) {
1265 if (i > 0) {
1266 buffer.append(getArraySeparator());
1267 }
1268 appendDetail(buffer, fieldName, array[i]);
1269 }
1270 buffer.append(getArrayEnd());
1271 }
1272
1273 /**
1274 * Appends to the {@code toString} a {@code long} value.
1275 *
1276 * @param buffer the {@link StringBuffer} to populate.
1277 * @param fieldName the field name, typically not used as already appended.
1278 * @param value the value to add to the {@code toString}.
1279 */
1280 protected void appendDetail(final StringBuffer buffer, final String fieldName, final long value) {
1281 buffer.append(value);
1282 }
1283
1284 /**
1285 * Appends to the {@code toString} the detail of a {@code long} array.
1286 *
1287 * @param buffer the {@link StringBuffer} to populate.
1288 * @param fieldName the field name, typically not used as already appended.
1289 * @param array the array to add to the {@code toString}, not {@code null}.
1290 */
1291 protected void appendDetail(final StringBuffer buffer, final String fieldName, final long[] array) {
1292 buffer.append(getArrayStart());
1293 for (int i = 0; i < array.length; i++) {
1294 if (i > 0) {
1295 buffer.append(getArraySeparator());
1296 }
1297 appendDetail(buffer, fieldName, array[i]);
1298 }
1299 buffer.append(getArrayEnd());
1300 }
1301
1302 /**
1303 * Appends to the {@code toString} a {@link Map}.
1304 *
1305 * @param buffer the {@link StringBuffer} to populate.
1306 * @param fieldName the field name, typically not used as already appended.
1307 * @param map the {@link Map} to add to the {@code toString}, not {@code null}.
1308 */
1309 protected void appendDetail(final StringBuffer buffer, final String fieldName, final Map<?, ?> map) {
1310 buffer.append(map);
1311 }
1312
1313 /**
1314 * Appends to the {@code toString} an {@link Object} value, printing the full detail of the {@link Object}.
1315 *
1316 * @param buffer the {@link StringBuffer} to populate.
1317 * @param fieldName the field name, typically not used as already appended.
1318 * @param value the value to add to the {@code toString}, not {@code null}.
1319 */
1320 protected void appendDetail(final StringBuffer buffer, final String fieldName, final Object value) {
1321 buffer.append(value);
1322 }
1323
1324 /**
1325 * Appends to the {@code toString} the detail of an {@link Object} array.
1326 *
1327 * @param buffer the {@link StringBuffer} to populate.
1328 * @param fieldName the field name, typically not used as already appended.
1329 * @param array the array to add to the {@code toString}, not {@code null}.
1330 */
1331 protected void appendDetail(final StringBuffer buffer, final String fieldName, final Object[] array) {
1332 buffer.append(getArrayStart());
1333 for (int i = 0; i < array.length; i++) {
1334 appendDetail(buffer, fieldName, i, array[i]);
1335 }
1336 buffer.append(getArrayEnd());
1337 }
1338
1339 /**
1340 * Appends to the {@code toString} a {@code short} value.
1341 *
1342 * @param buffer the {@link StringBuffer} to populate.
1343 * @param fieldName the field name, typically not used as already appended.
1344 * @param value the value to add to the {@code toString}.
1345 */
1346 protected void appendDetail(final StringBuffer buffer, final String fieldName, final short value) {
1347 buffer.append(value);
1348 }
1349
1350 /**
1351 * Appends to the {@code toString} the detail of a {@code short} array.
1352 *
1353 * @param buffer the {@link StringBuffer} to populate.
1354 * @param fieldName the field name, typically not used as already appended.
1355 * @param array the array to add to the {@code toString}, not {@code null}.
1356 */
1357 protected void appendDetail(final StringBuffer buffer, final String fieldName, final short[] array) {
1358 buffer.append(getArrayStart());
1359 for (int i = 0; i < array.length; i++) {
1360 if (i > 0) {
1361 buffer.append(getArraySeparator());
1362 }
1363 appendDetail(buffer, fieldName, array[i]);
1364 }
1365 buffer.append(getArrayEnd());
1366 }
1367
1368 /**
1369 * Appends to the {@code toString} the end of data indicator.
1370 *
1371 * @param buffer the {@link StringBuffer} to populate.
1372 * @param object the {@link Object} to build a {@code toString} for.
1373 */
1374 public void appendEnd(final StringBuffer buffer, final Object object) {
1375 if (!isFieldSeparatorAtEnd()) {
1376 removeLastFieldSeparator(buffer);
1377 }
1378 appendContentEnd(buffer);
1379 unregister(object);
1380 }
1381
1382 /**
1383 * Appends to the {@code toString} the field end.
1384 *
1385 * @param buffer the {@link StringBuffer} to populate.
1386 * @param fieldName the field name, typically not used as already appended.
1387 */
1388 protected void appendFieldEnd(final StringBuffer buffer, final String fieldName) {
1389 appendFieldSeparator(buffer);
1390 }
1391
1392 /**
1393 * Appends to the {@code toString} the field separator.
1394 *
1395 * @param buffer the {@link StringBuffer} to populate.
1396 */
1397 protected void appendFieldSeparator(final StringBuffer buffer) {
1398 buffer.append(getFieldSeparator());
1399 }
1400
1401 /**
1402 * Appends to the {@code toString} the field start.
1403 *
1404 * @param buffer the {@link StringBuffer} to populate.
1405 * @param fieldName the field name.
1406 */
1407 protected void appendFieldStart(final StringBuffer buffer, final String fieldName) {
1408 if (isUseFieldNames() && fieldName != null) {
1409 buffer.append(fieldName);
1410 buffer.append(getFieldNameValueSeparator());
1411 }
1412 }
1413
1414 /**
1415 * Appends the {@link System#identityHashCode(java.lang.Object)}.
1416 *
1417 * @param buffer the {@link StringBuffer} to populate.
1418 * @param object the {@link Object} whose id to output.
1419 */
1420 protected void appendIdentityHashCode(final StringBuffer buffer, final Object object) {
1421 if (isUseIdentityHashCode() && object != null) {
1422 register(object);
1423 buffer.append('@');
1424 buffer.append(ObjectUtils.identityHashCodeHex(object));
1425 }
1426 }
1427
1428 /**
1429 * Appends to the {@code toString} an {@link Object}, correctly interpreting its type.
1430 *
1431 * <p>
1432 * 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
1433 * method.
1434 * </p>
1435 *
1436 * <p>
1437 * Either detail or summary views can be specified.
1438 * </p>
1439 *
1440 * <p>
1441 * If a cycle is detected, an object will be appended with the {@code Object.toString()} format.
1442 * </p>
1443 *
1444 * @param buffer the {@link StringBuffer} to populate.
1445 * @param fieldName the field name, typically not used as already appended.
1446 * @param value the value to add to the {@code toString}, not {@code null}.
1447 * @param detail output detail or not.
1448 */
1449 protected void appendInternal(final StringBuffer buffer, final String fieldName, final Object value, final boolean detail) {
1450 if (isRegistered(value) && !(value instanceof Number || value instanceof Boolean || value instanceof Character)) {
1451 appendCyclicObject(buffer, fieldName, value);
1452 return;
1453 }
1454 register(value);
1455 try {
1456 if (value instanceof Collection<?>) {
1457 if (detail) {
1458 appendDetail(buffer, fieldName, (Collection<?>) value);
1459 } else {
1460 appendSummarySize(buffer, fieldName, ((Collection<?>) value).size());
1461 }
1462 } else if (value instanceof Map<?, ?>) {
1463 if (detail) {
1464 appendDetail(buffer, fieldName, (Map<?, ?>) value);
1465 } else {
1466 appendSummarySize(buffer, fieldName, ((Map<?, ?>) value).size());
1467 }
1468 } else if (value instanceof long[]) {
1469 if (detail) {
1470 appendDetail(buffer, fieldName, (long[]) value);
1471 } else {
1472 appendSummary(buffer, fieldName, (long[]) value);
1473 }
1474 } else if (value instanceof int[]) {
1475 if (detail) {
1476 appendDetail(buffer, fieldName, (int[]) value);
1477 } else {
1478 appendSummary(buffer, fieldName, (int[]) value);
1479 }
1480 } else if (value instanceof short[]) {
1481 if (detail) {
1482 appendDetail(buffer, fieldName, (short[]) value);
1483 } else {
1484 appendSummary(buffer, fieldName, (short[]) value);
1485 }
1486 } else if (value instanceof byte[]) {
1487 if (detail) {
1488 appendDetail(buffer, fieldName, (byte[]) value);
1489 } else {
1490 appendSummary(buffer, fieldName, (byte[]) value);
1491 }
1492 } else if (value instanceof char[]) {
1493 if (detail) {
1494 appendDetail(buffer, fieldName, (char[]) value);
1495 } else {
1496 appendSummary(buffer, fieldName, (char[]) value);
1497 }
1498 } else if (value instanceof double[]) {
1499 if (detail) {
1500 appendDetail(buffer, fieldName, (double[]) value);
1501 } else {
1502 appendSummary(buffer, fieldName, (double[]) value);
1503 }
1504 } else if (value instanceof float[]) {
1505 if (detail) {
1506 appendDetail(buffer, fieldName, (float[]) value);
1507 } else {
1508 appendSummary(buffer, fieldName, (float[]) value);
1509 }
1510 } else if (value instanceof boolean[]) {
1511 if (detail) {
1512 appendDetail(buffer, fieldName, (boolean[]) value);
1513 } else {
1514 appendSummary(buffer, fieldName, (boolean[]) value);
1515 }
1516 } else if (ObjectUtils.isArray(value)) {
1517 if (detail) {
1518 appendDetail(buffer, fieldName, (Object[]) value);
1519 } else {
1520 appendSummary(buffer, fieldName, (Object[]) value);
1521 }
1522 } else if (detail) {
1523 appendDetail(buffer, fieldName, value);
1524 } else {
1525 appendSummary(buffer, fieldName, value);
1526 }
1527 } finally {
1528 unregister(value);
1529 }
1530 }
1531
1532 /**
1533 * Appends to the {@code toString} an indicator for {@code null}.
1534 *
1535 * <p>
1536 * The default indicator is {@code "<null>"}.
1537 * </p>
1538 *
1539 * @param buffer the {@link StringBuffer} to populate.
1540 * @param fieldName the field name, typically not used as already appended.
1541 */
1542 protected void appendNullText(final StringBuffer buffer, final String fieldName) {
1543 buffer.append(getNullText());
1544 }
1545
1546 /**
1547 * Appends to the {@code toString} the start of data indicator.
1548 *
1549 * @param buffer the {@link StringBuffer} to populate.
1550 * @param object the {@link Object} to build a {@code toString} for.
1551 */
1552 public void appendStart(final StringBuffer buffer, final Object object) {
1553 if (object != null) {
1554 appendClassName(buffer, object);
1555 appendIdentityHashCode(buffer, object);
1556 appendContentStart(buffer);
1557 if (isFieldSeparatorAtStart()) {
1558 appendFieldSeparator(buffer);
1559 }
1560 }
1561 }
1562
1563 /**
1564 * Appends to the {@code toString} a summary of a {@code boolean} array.
1565 *
1566 * @param buffer the {@link StringBuffer} to populate.
1567 * @param fieldName the field name, typically not used as already appended.
1568 * @param array the array to add to the {@code toString}, not {@code null}.
1569 */
1570 protected void appendSummary(final StringBuffer buffer, final String fieldName, final boolean[] array) {
1571 appendSummarySize(buffer, fieldName, array.length);
1572 }
1573
1574 /**
1575 * Appends to the {@code toString} a summary of a {@code byte} array.
1576 *
1577 * @param buffer the {@link StringBuffer} to populate.
1578 * @param fieldName the field name, typically not used as already appended.
1579 * @param array the array to add to the {@code toString}, not {@code null}.
1580 */
1581 protected void appendSummary(final StringBuffer buffer, final String fieldName, final byte[] array) {
1582 appendSummarySize(buffer, fieldName, array.length);
1583 }
1584
1585 /**
1586 * Appends to the {@code toString} a summary of a {@code char} array.
1587 *
1588 * @param buffer the {@link StringBuffer} to populate.
1589 * @param fieldName the field name, typically not used as already appended.
1590 * @param array the array to add to the {@code toString}, not {@code null}.
1591 */
1592 protected void appendSummary(final StringBuffer buffer, final String fieldName, final char[] array) {
1593 appendSummarySize(buffer, fieldName, array.length);
1594 }
1595
1596 /**
1597 * Appends to the {@code toString} a summary of a {@code double} array.
1598 *
1599 * @param buffer the {@link StringBuffer} to populate
1600 * @param fieldName the field name, typically not used as already appended
1601 * @param array the array to add to the {@code toString}, not {@code null}
1602 */
1603 protected void appendSummary(final StringBuffer buffer, final String fieldName, final double[] array) {
1604 appendSummarySize(buffer, fieldName, array.length);
1605 }
1606
1607 /**
1608 * Appends to the {@code toString} a summary of a {@code float} array.
1609 *
1610 * @param buffer the {@link StringBuffer} to populate.
1611 * @param fieldName the field name, typically not used as already appended.
1612 * @param array the array to add to the {@code toString}, not {@code null}.
1613 */
1614 protected void appendSummary(final StringBuffer buffer, final String fieldName, final float[] array) {
1615 appendSummarySize(buffer, fieldName, array.length);
1616 }
1617
1618 /**
1619 * Appends to the {@code toString} a summary of an {@code int} array.
1620 *
1621 * @param buffer the {@link StringBuffer} to populate.
1622 * @param fieldName the field name, typically not used as already appended.
1623 * @param array the array to add to the {@code toString}, not {@code null}.
1624 */
1625 protected void appendSummary(final StringBuffer buffer, final String fieldName, final int[] array) {
1626 appendSummarySize(buffer, fieldName, array.length);
1627 }
1628
1629 /**
1630 * Appends to the {@code toString} a summary of a {@code long} array.
1631 *
1632 * @param buffer the {@link StringBuffer} to populate.
1633 * @param fieldName the field name, typically not used as already appended.
1634 * @param array the array to add to the {@code toString}, not {@code null}.
1635 */
1636 protected void appendSummary(final StringBuffer buffer, final String fieldName, final long[] array) {
1637 appendSummarySize(buffer, fieldName, array.length);
1638 }
1639
1640 /**
1641 * Appends to the {@code toString} an {@link Object} value, printing a summary of the {@link Object}.
1642 *
1643 * @param buffer the {@link StringBuffer} to populate.
1644 * @param fieldName the field name, typically not used as already appended.
1645 * @param value the value to add to the {@code toString}, not {@code null}.
1646 */
1647 protected void appendSummary(final StringBuffer buffer, final String fieldName, final Object value) {
1648 buffer.append(getSummaryObjectStartText());
1649 buffer.append(getShortClassName(value.getClass()));
1650 buffer.append(getSummaryObjectEndText());
1651 }
1652
1653 /**
1654 * Appends to the {@code toString} a summary of an {@link Object} array.
1655 *
1656 * @param buffer the {@link StringBuffer} to populate.
1657 * @param fieldName the field name, typically not used as already appended.
1658 * @param array the array to add to the {@code toString}, not {@code null}.
1659 */
1660 protected void appendSummary(final StringBuffer buffer, final String fieldName, final Object[] array) {
1661 appendSummarySize(buffer, fieldName, array.length);
1662 }
1663
1664 /**
1665 * Appends to the {@code toString} a summary of a {@code short} array.
1666 *
1667 * @param buffer the {@link StringBuffer} to populate.
1668 * @param fieldName the field name, typically not used as already appended.
1669 * @param array the array to add to the {@code toString}, not {@code null}.
1670 */
1671 protected void appendSummary(final StringBuffer buffer, final String fieldName, final short[] array) {
1672 appendSummarySize(buffer, fieldName, array.length);
1673 }
1674
1675 /**
1676 * Appends to the {@code toString} a size summary.
1677 *
1678 * <p>
1679 * The size summary is used to summarize the contents of {@link Collection}s, {@link Map}s and arrays.
1680 * </p>
1681 *
1682 * <p>
1683 * The output consists of a prefix, the passed in size and a suffix.
1684 * </p>
1685 *
1686 * <p>
1687 * The default format is {@code "<size=n>"}.
1688 * </p>
1689 *
1690 * @param buffer the {@link StringBuffer} to populate.
1691 * @param fieldName the field name, typically not used as already appended.
1692 * @param size the size to append.
1693 */
1694 protected void appendSummarySize(final StringBuffer buffer, final String fieldName, final int size) {
1695 buffer.append(getSizeStartText());
1696 buffer.append(size);
1697 buffer.append(getSizeEndText());
1698 }
1699
1700 /**
1701 * Appends to the {@code toString} the superclass toString.
1702 * <p>
1703 * NOTE: It assumes that the toString has been created from the same ToStringStyle.
1704 * </p>
1705 *
1706 * <p>
1707 * A {@code null} {@code superToString} is ignored.
1708 * </p>
1709 *
1710 * @param buffer the {@link StringBuffer} to populate.
1711 * @param superToString the {@code super.toString()}.
1712 * @since 2.0
1713 */
1714 public void appendSuper(final StringBuffer buffer, final String superToString) {
1715 appendToString(buffer, superToString);
1716 }
1717
1718 /**
1719 * Appends to the {@code toString} another toString.
1720 * <p>
1721 * NOTE: It assumes that the toString has been created from the same ToStringStyle.
1722 * </p>
1723 *
1724 * <p>
1725 * A {@code null} {@code toString} is ignored.
1726 * </p>
1727 *
1728 * @param buffer the {@link StringBuffer} to populate.
1729 * @param toString the additional {@code toString}.
1730 * @since 2.0
1731 */
1732 public void appendToString(final StringBuffer buffer, final String toString) {
1733 if (toString != null) {
1734 final int pos1 = toString.indexOf(getContentStart()) + getContentStart().length();
1735 final int pos2 = toString.lastIndexOf(getContentEnd());
1736 if (pos1 != pos2 && pos1 >= 0 && pos2 >= 0) {
1737 if (isFieldSeparatorAtStart()) {
1738 removeLastFieldSeparator(buffer);
1739 }
1740 buffer.append(toString, pos1, pos2);
1741 appendFieldSeparator(buffer);
1742 }
1743 }
1744 }
1745
1746 /**
1747 * Gets the array end text.
1748 *
1749 * @return the current array end text.
1750 */
1751 protected String getArrayEnd() {
1752 return arrayEnd;
1753 }
1754
1755 /**
1756 * Gets the array separator text.
1757 *
1758 * @return the current array separator text.
1759 */
1760 protected String getArraySeparator() {
1761 return arraySeparator;
1762 }
1763
1764 /**
1765 * Gets the array start text.
1766 *
1767 * @return the current array start text.
1768 */
1769 protected String getArrayStart() {
1770 return arrayStart;
1771 }
1772
1773 /**
1774 * Gets the content end text.
1775 *
1776 * @return the current content end text.
1777 */
1778 protected String getContentEnd() {
1779 return contentEnd;
1780 }
1781
1782 /**
1783 * Gets the content start text.
1784 *
1785 * @return the current content start text.
1786 */
1787 protected String getContentStart() {
1788 return contentStart;
1789 }
1790
1791 /**
1792 * Gets the field name value separator text.
1793 *
1794 * @return the current field name value separator text.
1795 */
1796 protected String getFieldNameValueSeparator() {
1797 return fieldNameValueSeparator;
1798 }
1799
1800 /**
1801 * Gets the field separator text.
1802 *
1803 * @return the current field separator text.
1804 */
1805 protected String getFieldSeparator() {
1806 return fieldSeparator;
1807 }
1808
1809 /**
1810 * Gets the text to output when {@code null} found.
1811 *
1812 * @return the current text to output when null found.
1813 */
1814 protected String getNullText() {
1815 return nullText;
1816 }
1817
1818 /**
1819 * Gets the short class name for a class.
1820 *
1821 * <p>
1822 * The short class name is the class name excluding the package name.
1823 * </p>
1824 *
1825 * @param cls the {@link Class} to get the short name of.
1826 * @return the short name.
1827 */
1828 protected String getShortClassName(final Class<?> cls) {
1829 return ClassUtils.getShortClassName(cls);
1830 }
1831
1832 /**
1833 * Gets the end text to output when a {@link Collection}, {@link Map} or array size is output.
1834 *
1835 * <p>
1836 * This is output after the size value.
1837 * </p>
1838 *
1839 * @return the current end of size text.
1840 */
1841 protected String getSizeEndText() {
1842 return sizeEndText;
1843 }
1844
1845 /**
1846 * Gets the start text to output when a {@link Collection}, {@link Map} or array size is output.
1847 *
1848 * <p>
1849 * This is output before the size value.
1850 * </p>
1851 *
1852 * @return the current start of size text.
1853 */
1854 protected String getSizeStartText() {
1855 return sizeStartText;
1856 }
1857
1858 /**
1859 * Gets the end text to output when an {@link Object} is output in summary mode.
1860 *
1861 * <p>
1862 * This is output after the size value.
1863 * </p>
1864 *
1865 * @return the current end of summary text.
1866 */
1867 protected String getSummaryObjectEndText() {
1868 return summaryObjectEndText;
1869 }
1870
1871 /**
1872 * Gets the start text to output when an {@link Object} is output in summary mode.
1873 *
1874 * <p>
1875 * This is output before the size value.
1876 * </p>
1877 *
1878 * @return the current start of summary text.
1879 */
1880 protected String getSummaryObjectStartText() {
1881 return summaryObjectStartText;
1882 }
1883
1884 /**
1885 * Gets whether to output array content detail.
1886 *
1887 * @return the current array content detail setting.
1888 */
1889 protected boolean isArrayContentDetail() {
1890 return arrayContentDetail;
1891 }
1892
1893 /**
1894 * Gets whether to use full detail when the caller doesn't specify.
1895 *
1896 * @return the current defaultFullDetail flag.
1897 */
1898 protected boolean isDefaultFullDetail() {
1899 return defaultFullDetail;
1900 }
1901
1902 /**
1903 * Gets whether the field separator should be added at the end of each buffer.
1904 *
1905 * @return fieldSeparatorAtEnd flag.
1906 * @since 2.0
1907 */
1908 protected boolean isFieldSeparatorAtEnd() {
1909 return fieldSeparatorAtEnd;
1910 }
1911
1912 /**
1913 * Gets whether the field separator should be added at the start of each buffer.
1914 *
1915 * @return the fieldSeparatorAtStart flag.
1916 * @since 2.0
1917 */
1918 protected boolean isFieldSeparatorAtStart() {
1919 return fieldSeparatorAtStart;
1920 }
1921
1922 /**
1923 * Is this field to be output in full detail.
1924 *
1925 * <p>
1926 * 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
1927 * 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
1928 * detail level is used.
1929 * </p>
1930 *
1931 * @param fullDetailRequest the detail level requested.
1932 * @return whether full detail is to be shown.
1933 */
1934 protected boolean isFullDetail(final Boolean fullDetailRequest) {
1935 if (fullDetailRequest == null) {
1936 return isDefaultFullDetail();
1937 }
1938 return fullDetailRequest.booleanValue();
1939 }
1940
1941 // Setters and getters for the customizable parts of the style
1942 // These methods are not expected to be overridden, except to make public
1943 // (They are not public so that immutable subclasses can be written)
1944 /**
1945 * Gets whether to use the class name.
1946 *
1947 * @return the current useClassName flag.
1948 */
1949 protected boolean isUseClassName() {
1950 return useClassName;
1951 }
1952
1953 /**
1954 * Gets whether to use the field names passed in.
1955 *
1956 * @return the current useFieldNames flag.
1957 */
1958 protected boolean isUseFieldNames() {
1959 return useFieldNames;
1960 }
1961
1962 /**
1963 * Gets whether to use the identity hash code.
1964 *
1965 * @return the current useIdentityHashCode flag.
1966 */
1967 protected boolean isUseIdentityHashCode() {
1968 return useIdentityHashCode;
1969 }
1970
1971 /**
1972 * Gets whether to output short or long class names.
1973 *
1974 * @return the current useShortClassName flag.
1975 * @since 2.0
1976 */
1977 protected boolean isUseShortClassName() {
1978 return useShortClassName;
1979 }
1980
1981 /**
1982 * Appends to the {@code toString} the detail of an array type.
1983 *
1984 * @param buffer the {@link StringBuffer} to populate.
1985 * @param fieldName the field name, typically not used as already appended.
1986 * @param array the array to add to the {@code toString}, not {@code null}.
1987 * @since 2.0
1988 */
1989 protected void reflectionAppendArrayDetail(final StringBuffer buffer, final String fieldName, final Object array) {
1990 buffer.append(getArrayStart());
1991 final int length = Array.getLength(array);
1992 for (int i = 0; i < length; i++) {
1993 appendDetail(buffer, fieldName, i, Array.get(array, i));
1994 }
1995 buffer.append(getArrayEnd());
1996 }
1997
1998 /**
1999 * Remove the last field separator from the buffer.
2000 *
2001 * @param buffer the {@link StringBuffer} to populate.
2002 * @since 2.0
2003 */
2004 protected void removeLastFieldSeparator(final StringBuffer buffer) {
2005 if (Strings.CS.endsWith(buffer, getFieldSeparator())) {
2006 buffer.setLength(buffer.length() - getFieldSeparator().length());
2007 }
2008 }
2009
2010 /**
2011 * Sets whether to output array content detail.
2012 *
2013 * @param arrayContentDetail the new arrayContentDetail flag.
2014 */
2015 protected void setArrayContentDetail(final boolean arrayContentDetail) {
2016 this.arrayContentDetail = arrayContentDetail;
2017 }
2018
2019 /**
2020 * Sets the array end text.
2021 *
2022 * <p>
2023 * {@code null} is accepted, but will be converted to an empty String.
2024 * </p>
2025 *
2026 * @param arrayEnd the new array end text.
2027 */
2028 protected void setArrayEnd(final String arrayEnd) {
2029 this.arrayEnd = ObjectUtils.toString(arrayEnd);
2030 }
2031
2032 /**
2033 * Sets the array separator text.
2034 *
2035 * <p>
2036 * {@code null} is accepted, but will be converted to an empty String.
2037 * </p>
2038 *
2039 * @param arraySeparator the new array separator text.
2040 */
2041 protected void setArraySeparator(final String arraySeparator) {
2042 this.arraySeparator = ObjectUtils.toString(arraySeparator);
2043 }
2044
2045 /**
2046 * Sets the array start text.
2047 *
2048 * <p>
2049 * {@code null} is accepted, but will be converted to an empty String.
2050 * </p>
2051 *
2052 * @param arrayStart the new array start text.
2053 */
2054 protected void setArrayStart(final String arrayStart) {
2055 this.arrayStart = ObjectUtils.toString(arrayStart);
2056 }
2057
2058 /**
2059 * Sets the content end text.
2060 *
2061 * <p>
2062 * {@code null} is accepted, but will be converted to an empty String.
2063 * </p>
2064 *
2065 * @param contentEnd the new content end text.
2066 */
2067 protected void setContentEnd(final String contentEnd) {
2068 this.contentEnd = ObjectUtils.toString(contentEnd);
2069 }
2070
2071 /**
2072 * Sets the content start text.
2073 *
2074 * <p>
2075 * {@code null} is accepted, but will be converted to an empty String.
2076 * </p>
2077 *
2078 * @param contentStart the new content start text.
2079 */
2080 protected void setContentStart(final String contentStart) {
2081 this.contentStart = ObjectUtils.toString(contentStart);
2082 }
2083
2084 /**
2085 * Sets whether to use full detail when the caller doesn't specify.
2086 *
2087 * @param defaultFullDetail the new defaultFullDetail flag.
2088 */
2089 protected void setDefaultFullDetail(final boolean defaultFullDetail) {
2090 this.defaultFullDetail = defaultFullDetail;
2091 }
2092
2093 /**
2094 * Sets the field name value separator text.
2095 *
2096 * <p>
2097 * {@code null} is accepted, but will be converted to an empty String.
2098 * </p>
2099 *
2100 * @param fieldNameValueSeparator the new field name value separator text.
2101 */
2102 protected void setFieldNameValueSeparator(final String fieldNameValueSeparator) {
2103 this.fieldNameValueSeparator = ObjectUtils.toString(fieldNameValueSeparator);
2104 }
2105
2106 /**
2107 * Sets the field separator text.
2108 *
2109 * <p>
2110 * {@code null} is accepted, but will be converted to an empty String.
2111 * </p>
2112 *
2113 * @param fieldSeparator the new field separator text.
2114 */
2115 protected void setFieldSeparator(final String fieldSeparator) {
2116 this.fieldSeparator = ObjectUtils.toString(fieldSeparator);
2117 }
2118
2119 /**
2120 * Sets whether the field separator should be added at the end of each buffer.
2121 *
2122 * @param fieldSeparatorAtEnd the fieldSeparatorAtEnd flag.
2123 * @since 2.0
2124 */
2125 protected void setFieldSeparatorAtEnd(final boolean fieldSeparatorAtEnd) {
2126 this.fieldSeparatorAtEnd = fieldSeparatorAtEnd;
2127 }
2128
2129 /**
2130 * Sets whether the field separator should be added at the start of each buffer.
2131 *
2132 * @param fieldSeparatorAtStart the fieldSeparatorAtStart flag.
2133 * @since 2.0
2134 */
2135 protected void setFieldSeparatorAtStart(final boolean fieldSeparatorAtStart) {
2136 this.fieldSeparatorAtStart = fieldSeparatorAtStart;
2137 }
2138
2139 /**
2140 * Sets the text to output when {@code null} found.
2141 *
2142 * <p>
2143 * {@code null} is accepted, but will be converted to an empty String.
2144 * </p>
2145 *
2146 * @param nullText the new text to output when null found.
2147 */
2148 protected void setNullText(final String nullText) {
2149 this.nullText = ObjectUtils.toString(nullText);
2150 }
2151
2152 /**
2153 * Sets the end text to output when a {@link Collection}, {@link Map} or array size is output.
2154 *
2155 * <p>
2156 * This is output after the size value.
2157 * </p>
2158 *
2159 * <p>
2160 * {@code null} is accepted, but will be converted to an empty String.
2161 * </p>
2162 *
2163 * @param sizeEndText the new end of size text.
2164 */
2165 protected void setSizeEndText(final String sizeEndText) {
2166 this.sizeEndText = ObjectUtils.toString(sizeEndText);
2167 }
2168
2169 /**
2170 * Sets the start text to output when a {@link Collection}, {@link Map} or array size is output.
2171 *
2172 * <p>
2173 * This is output before the size value.
2174 * </p>
2175 *
2176 * <p>
2177 * {@code null} is accepted, but will be converted to an empty String.
2178 * </p>
2179 *
2180 * @param sizeStartText the new start of size text.
2181 */
2182 protected void setSizeStartText(final String sizeStartText) {
2183 this.sizeStartText = ObjectUtils.toString(sizeStartText);
2184 }
2185
2186 /**
2187 * Sets the end text to output when an {@link Object} is output in summary mode.
2188 *
2189 * <p>
2190 * This is output after the size value.
2191 * </p>
2192 *
2193 * <p>
2194 * {@code null} is accepted, but will be converted to an empty String.
2195 * </p>
2196 *
2197 * @param summaryObjectEndText the new end of summary text.
2198 */
2199 protected void setSummaryObjectEndText(final String summaryObjectEndText) {
2200 this.summaryObjectEndText = ObjectUtils.toString(summaryObjectEndText);
2201 }
2202
2203 /**
2204 * Sets the start text to output when an {@link Object} is output in summary mode.
2205 *
2206 * <p>
2207 * This is output before the size value.
2208 * </p>
2209 *
2210 * <p>
2211 * {@code null} is accepted, but will be converted to an empty String.
2212 * </p>
2213 *
2214 * @param summaryObjectStartText the new start of summary text.
2215 */
2216 protected void setSummaryObjectStartText(final String summaryObjectStartText) {
2217 this.summaryObjectStartText = ObjectUtils.toString(summaryObjectStartText);
2218 }
2219
2220 /**
2221 * Sets whether to use the class name.
2222 *
2223 * @param useClassName the new useClassName flag.
2224 */
2225 protected void setUseClassName(final boolean useClassName) {
2226 this.useClassName = useClassName;
2227 }
2228
2229 /**
2230 * Sets whether to use the field names passed in.
2231 *
2232 * @param useFieldNames the new useFieldNames flag.
2233 */
2234 protected void setUseFieldNames(final boolean useFieldNames) {
2235 this.useFieldNames = useFieldNames;
2236 }
2237
2238 /**
2239 * Sets whether to use the identity hash code.
2240 *
2241 * @param useIdentityHashCode the new useIdentityHashCode flag.
2242 */
2243 protected void setUseIdentityHashCode(final boolean useIdentityHashCode) {
2244 this.useIdentityHashCode = useIdentityHashCode;
2245 }
2246
2247 /**
2248 * Sets whether to output short or long class names.
2249 *
2250 * @param useShortClassName the new useShortClassName flag.
2251 * @since 2.0
2252 */
2253 protected void setUseShortClassName(final boolean useShortClassName) {
2254 this.useShortClassName = useShortClassName;
2255 }
2256 }