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.lang.reflect.Field;
21 import java.lang.reflect.Modifier;
22 import java.util.Arrays;
23 import java.util.Collection;
24 import java.util.Comparator;
25 import java.util.Objects;
26
27 import org.apache.commons.lang3.ArraySorter;
28 import org.apache.commons.lang3.ArrayUtils;
29 import org.apache.commons.lang3.ClassUtils;
30 import org.apache.commons.lang3.stream.Streams;
31
32 /**
33 * Assists in implementing {@link Object#toString()} methods using reflection.
34 *
35 * <p>
36 * This class uses reflection to determine the fields to append. Because these fields are usually private, the class
37 * uses {@link java.lang.reflect.AccessibleObject#setAccessible(java.lang.reflect.AccessibleObject[], boolean)} to
38 * change the visibility of the fields. This will fail under a security manager, unless the appropriate permissions are
39 * set up correctly.
40 * </p>
41 * <p>
42 * Using reflection to access (private) fields circumvents any synchronization protection guarding access to these
43 * fields. If a toString method cannot safely read a field, you should exclude it from the toString method, or use
44 * synchronization consistent with the class' lock management around the invocation of the method. Take special care to
45 * exclude non-thread-safe collection classes, because these classes may throw ConcurrentModificationException if
46 * modified while the toString method is executing.
47 * </p>
48 * <p>
49 * A typical invocation for this method would look like:
50 * </p>
51 * <pre>
52 * public String toString() {
53 * return ReflectionToStringBuilder.toString(this);
54 * }
55 * </pre>
56 * <p>
57 * You can also use the builder to debug 3rd party objects:
58 * </p>
59 * <pre>
60 * System.out.println("An object: " + ReflectionToStringBuilder.toString(anObject));
61 * </pre>
62 * <p>
63 * A subclass can control field output by overriding the methods:
64 * </p>
65 * <ul>
66 * <li>{@link #accept(java.lang.reflect.Field)}</li>
67 * <li>{@link #getValue(java.lang.reflect.Field)}</li>
68 * </ul>
69 * <p>
70 * For example, this method does <em>not</em> include the {@code password} field in the returned {@link String}:
71 * </p>
72 * <pre>
73 * public String toString() {
74 * return (new ReflectionToStringBuilder(this) {
75 * protected boolean accept(Field f) {
76 * return super.accept(f) && !f.getName().equals("password");
77 * }
78 * }).toString();
79 * }
80 * </pre>
81 * <p>
82 * Alternatively the {@link ToStringExclude} annotation can be used to exclude fields from being incorporated in the
83 * result.
84 * </p>
85 * <p>
86 * It is also possible to use the {@link ToStringSummary} annotation to output the summary information instead of the
87 * detailed information of a field.
88 * </p>
89 * <p>
90 * The exact format of the {@code toString} is determined by the {@link ToStringStyle} passed into the constructor.
91 * </p>
92 *
93 * <p>
94 * <strong>Note:</strong> the default {@link ToStringStyle} will only do a "shallow" formatting, i.e. composed objects are not
95 * further traversed. To get "deep" formatting, use an instance of {@link RecursiveToStringStyle}.
96 * </p>
97 *
98 * @since 2.0
99 */
100 public class ReflectionToStringBuilder extends ToStringBuilder {
101
102 /**
103 * Converts the given Collection into an array of Strings. The returned array does not contain {@code null}
104 * entries. Note that {@link Arrays#sort(Object[])} will throw an {@link NullPointerException} if an array element
105 * is {@code null}.
106 *
107 * @param collection
108 * The collection to convert
109 * @return A new array of Strings.
110 */
111 static String[] toNoNullStringArray(final Collection<String> collection) {
112 if (collection == null) {
113 return ArrayUtils.EMPTY_STRING_ARRAY;
114 }
115 return toNoNullStringArray(collection.toArray());
116 }
117
118 /**
119 * Returns a new array of Strings without null elements. Internal method used to normalize exclude lists
120 * (arrays and collections). Note that {@link Arrays#sort(Object[])} will throw an {@link NullPointerException}
121 * if an array element is {@code null}.
122 *
123 * @param array
124 * The array to check
125 * @return The given array or a new array without null.
126 */
127 static String[] toNoNullStringArray(final Object[] array) {
128 return Streams.nonNull(array).map(Objects::toString).toArray(String[]::new);
129 }
130
131 /**
132 * Builds a {@code toString} value using the default {@link ToStringStyle} through reflection.
133 *
134 * <p>
135 * It uses {@code AccessibleObject.setAccessible} to gain access to private fields. This means that it will
136 * throw a security exception if run under a security manager, if the permissions are not set up correctly. It is
137 * also not as efficient as testing explicitly.
138 * </p>
139 *
140 * <p>
141 * Transient members will be not be included, as they are likely derived. Static fields will not be included.
142 * Superclass fields will be appended.
143 * </p>
144 *
145 * @param object
146 * the Object to be output
147 * @return The String result
148 * @throws IllegalArgumentException Thrown if the Object is {@code null}.
149 * @see ToStringExclude
150 * @see ToStringSummary
151 */
152 public static String toString(final Object object) {
153 return toString(object, null, false, false, null);
154 }
155
156 /**
157 * Builds a {@code toString} value through reflection.
158 *
159 * <p>
160 * It uses {@code AccessibleObject.setAccessible} to gain access to private fields. This means that it will
161 * throw a security exception if run under a security manager, if the permissions are not set up correctly. It is
162 * also not as efficient as testing explicitly.
163 * </p>
164 *
165 * <p>
166 * Transient members will be not be included, as they are likely derived. Static fields will not be included.
167 * Superclass fields will be appended.
168 * </p>
169 *
170 * <p>
171 * If the style is {@code null}, the default {@link ToStringStyle} is used.
172 * </p>
173 *
174 * @param object
175 * the Object to be output
176 * @param style
177 * the style of the {@code toString} to create, may be {@code null}
178 * @return The String result
179 * @throws IllegalArgumentException Thrown if the Object or {@link ToStringStyle} is {@code null}.
180 * @see ToStringExclude
181 * @see ToStringSummary
182 */
183 public static String toString(final Object object, final ToStringStyle style) {
184 return toString(object, style, false, false, null);
185 }
186
187 /**
188 * Builds a {@code toString} value through reflection.
189 *
190 * <p>
191 * It uses {@code AccessibleObject.setAccessible} to gain access to private fields. This means that it will
192 * throw a security exception if run under a security manager, if the permissions are not set up correctly. It is
193 * also not as efficient as testing explicitly.
194 * </p>
195 *
196 * <p>
197 * If the {@code outputTransients} is {@code true}, transient members will be output, otherwise they
198 * are ignored, as they are likely derived fields, and not part of the value of the Object.
199 * </p>
200 *
201 * <p>
202 * Static fields will not be included. Superclass fields will be appended.
203 * </p>
204 *
205 * <p>
206 * If the style is {@code null}, the default {@link ToStringStyle} is used.
207 * </p>
208 *
209 * @param object
210 * the Object to be output
211 * @param style
212 * the style of the {@code toString} to create, may be {@code null}
213 * @param outputTransients
214 * whether to include transient fields
215 * @return The String result
216 * @throws IllegalArgumentException Thrown if the Object is {@code null}.
217 * @see ToStringExclude
218 * @see ToStringSummary
219 */
220 public static String toString(final Object object, final ToStringStyle style, final boolean outputTransients) {
221 return toString(object, style, outputTransients, false, null);
222 }
223
224 /**
225 * Builds a {@code toString} value through reflection.
226 *
227 * <p>
228 * It uses {@code AccessibleObject.setAccessible} to gain access to private fields. This means that it will
229 * throw a security exception if run under a security manager, if the permissions are not set up correctly. It is
230 * also not as efficient as testing explicitly.
231 * </p>
232 *
233 * <p>
234 * If the {@code outputTransients} is {@code true}, transient fields will be output, otherwise they
235 * are ignored, as they are likely derived fields, and not part of the value of the Object.
236 * </p>
237 *
238 * <p>
239 * If the {@code outputStatics} is {@code true}, static fields will be output, otherwise they are
240 * ignored.
241 * </p>
242 *
243 * <p>
244 * Static fields will not be included. Superclass fields will be appended.
245 * </p>
246 *
247 * <p>
248 * If the style is {@code null}, the default {@link ToStringStyle} is used.
249 * </p>
250 *
251 * @param object
252 * the Object to be output
253 * @param style
254 * the style of the {@code toString} to create, may be {@code null}
255 * @param outputTransients
256 * whether to include transient fields
257 * @param outputStatics
258 * whether to include static fields
259 * @return The String result
260 * @throws IllegalArgumentException Thrown if the Object is {@code null}.
261 * @see ToStringExclude
262 * @see ToStringSummary
263 * @since 2.1
264 */
265 public static String toString(final Object object, final ToStringStyle style, final boolean outputTransients, final boolean outputStatics) {
266 return toString(object, style, outputTransients, outputStatics, null);
267 }
268
269 /**
270 * Builds a {@code toString} value through reflection.
271 *
272 * <p>
273 * It uses {@code AccessibleObject.setAccessible} to gain access to private fields. This means that it will
274 * throw a security exception if run under a security manager, if the permissions are not set up correctly. It is
275 * also not as efficient as testing explicitly.
276 * </p>
277 *
278 * <p>
279 * If the {@code outputTransients} is {@code true}, transient fields will be output, otherwise they
280 * are ignored, as they are likely derived fields, and not part of the value of the Object.
281 * </p>
282 *
283 * <p>
284 * If the {@code outputStatics} is {@code true}, static fields will be output, otherwise they are
285 * ignored.
286 * </p>
287 *
288 * <p>
289 * Superclass fields will be appended up to and including the specified superclass. A null superclass is treated as
290 * {@link Object}.
291 * </p>
292 *
293 * <p>
294 * If the style is {@code null}, the default {@link ToStringStyle} is used.
295 * </p>
296 *
297 * @param <T>
298 * the type of the object
299 * @param object
300 * the Object to be output
301 * @param style
302 * the style of the {@code toString} to create, may be {@code null}
303 * @param outputTransients
304 * whether to include transient fields
305 * @param outputStatics
306 * whether to include static fields
307 * @param excludeNullValues
308 * whether to exclude fields whose values are null
309 * @param reflectUpToClass
310 * the superclass to reflect up to (inclusive), may be {@code null}
311 * @return The String result
312 * @throws IllegalArgumentException Thrown if the Object is {@code null}.
313 * @see ToStringExclude
314 * @see ToStringSummary
315 * @since 3.6
316 */
317 public static <T> String toString(
318 final T object, final ToStringStyle style, final boolean outputTransients,
319 final boolean outputStatics, final boolean excludeNullValues, final Class<? super T> reflectUpToClass) {
320 return new ReflectionToStringBuilder(object, style, null, reflectUpToClass, outputTransients, outputStatics, excludeNullValues)
321 .toString();
322 }
323
324 /**
325 * Builds a {@code toString} value through reflection.
326 *
327 * <p>
328 * It uses {@code AccessibleObject.setAccessible} to gain access to private fields. This means that it will
329 * throw a security exception if run under a security manager, if the permissions are not set up correctly. It is
330 * also not as efficient as testing explicitly.
331 * </p>
332 *
333 * <p>
334 * If the {@code outputTransients} is {@code true}, transient fields will be output, otherwise they
335 * are ignored, as they are likely derived fields, and not part of the value of the Object.
336 * </p>
337 *
338 * <p>
339 * If the {@code outputStatics} is {@code true}, static fields will be output, otherwise they are
340 * ignored.
341 * </p>
342 *
343 * <p>
344 * Superclass fields will be appended up to and including the specified superclass. A null superclass is treated as
345 * {@link Object}.
346 * </p>
347 *
348 * <p>
349 * If the style is {@code null}, the default {@link ToStringStyle} is used.
350 * </p>
351 *
352 * @param <T>
353 * the type of the object
354 * @param object
355 * the Object to be output
356 * @param style
357 * the style of the {@code toString} to create, may be {@code null}
358 * @param outputTransients
359 * whether to include transient fields
360 * @param outputStatics
361 * whether to include static fields
362 * @param reflectUpToClass
363 * the superclass to reflect up to (inclusive), may be {@code null}
364 * @return The String result
365 * @throws IllegalArgumentException Thrown if the Object is {@code null}.
366 * @see ToStringExclude
367 * @see ToStringSummary
368 * @since 2.1
369 */
370 public static <T> String toString(
371 final T object, final ToStringStyle style, final boolean outputTransients,
372 final boolean outputStatics, final Class<? super T> reflectUpToClass) {
373 return new ReflectionToStringBuilder(object, style, null, reflectUpToClass, outputTransients, outputStatics)
374 .toString();
375 }
376
377 /**
378 * Builds a String for a toString method excluding the given field names.
379 *
380 * @param object
381 * The object to "toString".
382 * @param excludeFieldNames
383 * The field names to exclude. Null excludes nothing.
384 * @return The toString value.
385 */
386 public static String toStringExclude(final Object object, final Collection<String> excludeFieldNames) {
387 return toStringExclude(object, toNoNullStringArray(excludeFieldNames));
388 }
389
390 /**
391 * Builds a String for a toString method excluding the given field names.
392 *
393 * @param object
394 * The object to "toString".
395 * @param excludeFieldNames
396 * The field names to exclude
397 * @return The toString value.
398 */
399 public static String toStringExclude(final Object object, final String... excludeFieldNames) {
400 return new ReflectionToStringBuilder(object).setExcludeFieldNames(excludeFieldNames).toString();
401 }
402
403 /**
404 * Builds a String for a toString method including the given field names.
405 *
406 * @param object
407 * The object to "toString".
408 * @param includeFieldNames
409 * {@code null} or empty means all fields are included. All fields are included by default. This method will override the default behavior.
410 * @return The toString value.
411 * @since 3.13.0
412 */
413 public static String toStringInclude(final Object object, final Collection<String> includeFieldNames) {
414 return toStringInclude(object, toNoNullStringArray(includeFieldNames));
415 }
416
417 /**
418 * Builds a String for a toString method including the given field names.
419 *
420 * @param object
421 * The object to "toString".
422 * @param includeFieldNames
423 * The field names to include. {@code null} or empty means all fields are included. All fields are included by default. This method will override the default
424 * behavior.
425 * @return The toString value.
426 * @since 3.13.0
427 */
428 public static String toStringInclude(final Object object, final String... includeFieldNames) {
429 return new ReflectionToStringBuilder(object).setIncludeFieldNames(includeFieldNames).toString();
430 }
431
432 /**
433 * Whether or not to append static fields.
434 */
435 private boolean appendStatics;
436
437 /**
438 * Whether or not to append transient fields.
439 */
440 private boolean appendTransients;
441
442 /**
443 * Whether or not to append fields that are null.
444 */
445 private boolean excludeNullValues;
446
447 /**
448 * Which field names to exclude from output. Intended for fields like {@code "password"}.
449 *
450 * @since 3.0 this is protected instead of private
451 */
452 protected String[] excludeFieldNames;
453
454 /**
455 * Field names that will be included in the output. All fields are included by default.
456 *
457 * @since 3.13.0
458 */
459 protected String[] includeFieldNames;
460
461 /**
462 * The last super class to stop appending fields for.
463 */
464 private Class<?> upToClass;
465
466 /**
467 * Constructs a new instance.
468 *
469 * <p>
470 * This constructor outputs using the default style set with {@code setDefaultStyle}.
471 * </p>
472 *
473 * @param object
474 * the Object to build a {@code toString} for, must not be {@code null}
475 */
476 public ReflectionToStringBuilder(final Object object) {
477 super(object);
478 }
479
480 /**
481 * Constructs a new instance.
482 *
483 * <p>
484 * If the style is {@code null}, the default style is used.
485 * </p>
486 *
487 * @param object
488 * the Object to build a {@code toString} for, must not be {@code null}
489 * @param style
490 * the style of the {@code toString} to create, may be {@code null}
491 */
492 public ReflectionToStringBuilder(final Object object, final ToStringStyle style) {
493 super(object, style);
494 }
495
496 /**
497 * Constructs a new instance.
498 *
499 * <p>
500 * If the style is {@code null}, the default style is used.
501 * </p>
502 *
503 * <p>
504 * If the buffer is {@code null}, a new one is created.
505 * </p>
506 *
507 * @param object
508 * the Object to build a {@code toString} for
509 * @param style
510 * the style of the {@code toString} to create, may be {@code null}
511 * @param buffer
512 * the {@link StringBuffer} to populate, may be {@code null}
513 */
514 public ReflectionToStringBuilder(final Object object, final ToStringStyle style, final StringBuffer buffer) {
515 super(object, style, buffer);
516 }
517
518 /**
519 * Constructs a new instance.
520 *
521 * @param <T>
522 * the type of the object
523 * @param object
524 * the Object to build a {@code toString} for
525 * @param style
526 * the style of the {@code toString} to create, may be {@code null}
527 * @param buffer
528 * the {@link StringBuffer} to populate, may be {@code null}
529 * @param reflectUpToClass
530 * the superclass to reflect up to (inclusive), may be {@code null}
531 * @param outputTransients
532 * whether to include transient fields
533 * @param outputStatics
534 * whether to include static fields
535 * @since 2.1
536 */
537 public <T> ReflectionToStringBuilder(
538 final T object, final ToStringStyle style, final StringBuffer buffer,
539 final Class<? super T> reflectUpToClass, final boolean outputTransients, final boolean outputStatics) {
540 super(object, style, buffer);
541 setUpToClass(reflectUpToClass);
542 setAppendTransients(outputTransients);
543 setAppendStatics(outputStatics);
544 }
545
546 /**
547 * Constructs a new instance.
548 *
549 * @param <T>
550 * the type of the object
551 * @param object
552 * the Object to build a {@code toString} for
553 * @param style
554 * the style of the {@code toString} to create, may be {@code null}
555 * @param buffer
556 * the {@link StringBuffer} to populate, may be {@code null}
557 * @param reflectUpToClass
558 * the superclass to reflect up to (inclusive), may be {@code null}
559 * @param outputTransients
560 * whether to include transient fields
561 * @param outputStatics
562 * whether to include static fields
563 * @param excludeNullValues
564 * whether to exclude fields who value is null
565 * @since 3.6
566 */
567 public <T> ReflectionToStringBuilder(
568 final T object, final ToStringStyle style, final StringBuffer buffer,
569 final Class<? super T> reflectUpToClass, final boolean outputTransients, final boolean outputStatics,
570 final boolean excludeNullValues) {
571 super(object, style, buffer);
572 setUpToClass(reflectUpToClass);
573 setAppendTransients(outputTransients);
574 setAppendStatics(outputStatics);
575 setExcludeNullValues(excludeNullValues);
576 }
577
578 /**
579 * Returns whether or not to append the given {@link Field}.
580 * <ul>
581 * <li>Transient fields are appended only if {@link #isAppendTransients()} returns {@code true}.</li>
582 * <li>Static fields are appended only if {@link #isAppendStatics()} returns {@code true}.</li>
583 * <li>Inner class fields are not appended.</li>
584 * </ul>
585 *
586 * @param field
587 * The Field to test.
588 * @return Whether or not to append the given {@link Field}.
589 */
590 protected boolean accept(final Field field) {
591 if (field.getName().indexOf(ClassUtils.INNER_CLASS_SEPARATOR_CHAR) != -1) {
592 // Reject field from inner class.
593 return false;
594 }
595 if (Modifier.isTransient(field.getModifiers()) && !isAppendTransients()) {
596 // Reject transient fields.
597 return false;
598 }
599 if (Modifier.isStatic(field.getModifiers()) && !isAppendStatics()) {
600 // Reject static fields.
601 return false;
602 }
603 if (this.excludeFieldNames != null && Arrays.binarySearch(this.excludeFieldNames, field.getName()) >= 0) {
604 // Reject fields from the getExcludeFieldNames list.
605 return false;
606 }
607 if (ArrayUtils.isNotEmpty(includeFieldNames)) {
608 // Accept fields from the getIncludeFieldNames list. {@code null} or empty means all fields are included. All fields are included by default.
609 return Arrays.binarySearch(this.includeFieldNames, field.getName()) >= 0;
610 }
611 return !field.isAnnotationPresent(ToStringExclude.class);
612 }
613
614 /**
615 * Appends the fields and values defined by the given object of the given Class.
616 *
617 * <p>
618 * If a cycle is detected as an object is "toString()'ed", such an object is rendered as if
619 * {@code Object.toString()} had been called and not implemented by the object.
620 * </p>
621 *
622 * @param clazz
623 * The class of object parameter
624 */
625 protected void appendFieldsIn(final Class<?> clazz) {
626 if (clazz.isArray()) {
627 reflectionAppendArray(getObject());
628 return;
629 }
630 // The elements in the returned array are not sorted and are not in any particular order.
631 final Field[] fields = ArraySorter.sort(clazz.getDeclaredFields(), Comparator.comparing(Field::getName));
632 for (final Field field : fields) {
633 final String fieldName = field.getName();
634 if (accept(field)) {
635 setAccessible(field);
636 try {
637 // Warning: Field.get(Object) creates wrappers objects
638 // for primitive types.
639 final Object fieldValue = field.isAccessible() ? getValue(field) : null;
640 if (!excludeNullValues || fieldValue != null) {
641 this.append(fieldName, fieldValue, !field.isAnnotationPresent(ToStringSummary.class));
642 }
643 } catch (final IllegalAccessException e) {
644 // this can't happen. Would get a Security exception instead throw a runtime exception in case the
645 // impossible happens.
646 throw new IllegalStateException(e);
647 }
648 }
649 }
650 }
651
652 /**
653 * Gets the excludeFieldNames.
654 *
655 * @return The excludeFieldNames.
656 */
657 public String[] getExcludeFieldNames() {
658 return this.excludeFieldNames.clone();
659 }
660
661 /**
662 * Gets the includeFieldNames
663 *
664 * @return The includeFieldNames.
665 * @since 3.13.0
666 */
667 public String[] getIncludeFieldNames() {
668 return this.includeFieldNames.clone();
669 }
670
671 /**
672 * Gets the last super class to stop appending fields for.
673 *
674 * @return The last super class to stop appending fields for.
675 */
676 public Class<?> getUpToClass() {
677 return this.upToClass;
678 }
679
680 /**
681 * Gets the field value using {@code java.lang.reflect.Field.get(Object)}.
682 *
683 * @param field
684 * The Field to query.
685 * @return The Object from the given Field.
686 * @throws IllegalArgumentException Thrown as described in {@link java.lang.reflect.Field#get(Object)}.
687 * @throws IllegalAccessException Thrown as described in {@link java.lang.reflect.Field#get(Object)}.
688 * @see java.lang.reflect.Field#get(Object)
689 */
690 protected Object getValue(final Field field) throws IllegalAccessException {
691 return field.get(getObject());
692 }
693
694 /**
695 * Tests whether or not to append static fields.
696 *
697 * @return Whether or not to append static fields.
698 * @since 2.1
699 */
700 public boolean isAppendStatics() {
701 return this.appendStatics;
702 }
703
704 /**
705 * Tests whether or not to append transient fields.
706 *
707 * @return Whether or not to append transient fields.
708 */
709 public boolean isAppendTransients() {
710 return this.appendTransients;
711 }
712
713 /**
714 * Tests whether or not to append fields whose values are null.
715 *
716 * @return Whether or not to append fields whose values are null.
717 * @since 3.6
718 */
719 public boolean isExcludeNullValues() {
720 return this.excludeNullValues;
721 }
722
723 /**
724 * Appends to the {@code toString} an {@link Object} array.
725 *
726 * @param array
727 * the array to add to the {@code toString}
728 * @return {@code this} instance.
729 */
730 public ReflectionToStringBuilder reflectionAppendArray(final Object array) {
731 getStyle().reflectionAppendArrayDetail(getStringBuffer(), null, array);
732 return this;
733 }
734
735 /**
736 * Sets whether or not to append static fields.
737 *
738 * @param appendStatics
739 * Whether or not to append static fields.
740 * @since 2.1
741 */
742 public void setAppendStatics(final boolean appendStatics) {
743 this.appendStatics = appendStatics;
744 }
745
746 /**
747 * Sets whether or not to append transient fields.
748 *
749 * @param appendTransients
750 * Whether or not to append transient fields.
751 */
752 public void setAppendTransients(final boolean appendTransients) {
753 this.appendTransients = appendTransients;
754 }
755
756 /**
757 * Sets the field names to exclude.
758 *
759 * @param excludeFieldNamesParam
760 * The excludeFieldNames to excluding from toString or {@code null}.
761 * @return {@code this}
762 */
763 public ReflectionToStringBuilder setExcludeFieldNames(final String... excludeFieldNamesParam) {
764 if (excludeFieldNamesParam == null) {
765 this.excludeFieldNames = null;
766 } else {
767 // clone and remove nulls
768 this.excludeFieldNames = ArraySorter.sort(toNoNullStringArray(excludeFieldNamesParam));
769 }
770 return this;
771 }
772
773 /**
774 * Sets whether or not to append fields whose values are null.
775 *
776 * @param excludeNullValues
777 * Whether or not to append fields whose values are null.
778 * @since 3.6
779 */
780 public void setExcludeNullValues(final boolean excludeNullValues) {
781 this.excludeNullValues = excludeNullValues;
782 }
783
784 /**
785 * Sets the field names to include. {@code null} or empty means all fields are included. All fields are included by default. This method will override the default behavior.
786 *
787 * @param includeFieldNamesParam
788 * The includeFieldNames that must be on toString or {@code null}.
789 * @return {@code this}
790 * @since 3.13.0
791 */
792 public ReflectionToStringBuilder setIncludeFieldNames(final String... includeFieldNamesParam) {
793 if (includeFieldNamesParam == null) {
794 this.includeFieldNames = null;
795 } else {
796 // clone and remove nulls
797 this.includeFieldNames = ArraySorter.sort(toNoNullStringArray(includeFieldNamesParam));
798 }
799 return this;
800 }
801
802 /**
803 * Sets the last super class to stop appending fields for.
804 *
805 * @param clazz
806 * The last super class to stop appending fields for.
807 */
808 public void setUpToClass(final Class<?> clazz) {
809 if (clazz != null) {
810 final Object object = getObject();
811 if (object != null && !clazz.isInstance(object)) {
812 throw new IllegalArgumentException("Specified class is not a superclass of the object");
813 }
814 }
815 this.upToClass = clazz;
816 }
817
818 /**
819 * Gets the String built by this builder.
820 *
821 * @return The built string
822 */
823 @Override
824 public String toString() {
825 if (getObject() == null) {
826 return getStyle().getNullText();
827 }
828
829 validate();
830
831 Class<?> clazz = getObject().getClass();
832 appendFieldsIn(clazz);
833 while (clazz.getSuperclass() != null && clazz != getUpToClass()) {
834 clazz = clazz.getSuperclass();
835 appendFieldsIn(clazz);
836 }
837 return super.toString();
838 }
839
840 /**
841 * Validates that include and exclude names do not intersect.
842 */
843 private void validate() {
844 if (ArrayUtils.containsAny(this.excludeFieldNames, (Object[]) this.includeFieldNames)) {
845 ToStringStyle.unregister(getObject());
846 throw new IllegalStateException("includeFieldNames and excludeFieldNames must not intersect");
847 }
848 }
849
850 }