source: src/main/java/agents/org/apache/commons/lang/builder/ReflectionToStringBuilder.java

Last change on this file was 127, checked in by Wouter Pasman, 6 years ago

#41 ROLL BACK of rev.126 . So this version is equal to rev. 125

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