001    /*
002     *  Licensed to the Apache Software Foundation (ASF) under one
003     *  or more contributor license agreements.  See the NOTICE file
004     *  distributed with this work for additional information
005     *  regarding copyright ownership.  The ASF licenses this file
006     *  to you under the Apache License, Version 2.0 (the
007     *  "License"); you may not use this file except in compliance
008     *  with the License.  You may obtain a copy of the License at
009     *  
010     *    http://www.apache.org/licenses/LICENSE-2.0
011     *  
012     *  Unless required by applicable law or agreed to in writing,
013     *  software distributed under the License is distributed on an
014     *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015     *  KIND, either express or implied.  See the License for the
016     *  specific language governing permissions and limitations
017     *  under the License. 
018     *  
019     */
020    package org.apache.directory.shared.ldap.util;
021    
022    
023    import java.lang.reflect.AccessibleObject;
024    import java.lang.reflect.Field;
025    import java.lang.reflect.Modifier;
026    import java.util.HashSet;
027    import java.util.Set;
028    
029    
030    /**
031     * <p>
032     * Assists in implementing {@link Object#toString()}methods using reflection.
033     * </p>
034     * <p>
035     * This class uses reflection to determine the fields to append. Because these
036     * fields are usually private, the class uses
037     * {@link java.lang.reflect.AccessibleObject#setAccessible(java.lang.reflect.AccessibleObject[], boolean)}
038     * to change the visibility of the fields. This will fail under a security
039     * manager, unless the appropriate permissions are set up correctly.
040     * </p>
041     * <p>
042     * A typical invocation for this method would look like:
043     * </p>
044     * 
045     * <pre>
046     * public String toString()
047     * {
048     *     return ReflectionToStringBuilder.toString( this );
049     * }
050     * </pre>
051     * 
052     * <p>
053     * You can also use the builder to debug 3rd party objects:
054     * </p>
055     * 
056     * <pre>
057     * System.out.println( &quot;An object: &quot; + ReflectionToStringBuilder.toString( anObject ) );
058     * </pre>
059     * 
060     * <p>
061     * A subclass can control field output by overriding the methods:
062     * <ul>
063     * <li>{@link #accept(java.lang.reflect.Field)}</li>
064     * <li>{@link #getValue(java.lang.reflect.Field)}</li>
065     * </ul>
066     * </p>
067     * <p>
068     * For example, this method does <i>not</i> include the <code>password</code>
069     * field in the returned <code>String</code>:
070     * </p>
071     * 
072     * <pre>
073     * public String toString()
074     * {
075     *     return ( new ReflectionToStringBuilder( this )
076     *     {
077     *         protected boolean accept( Field f )
078     *         {
079     *             return super.accept( f ) &amp;&amp; !f.getName().equals( &quot;password&quot; );
080     *         }
081     *     } ).toString();
082     * }
083     * </pre>
084     * 
085     * <p>
086     * The exact format of the <code>toString</code> is determined by the
087     * {@link ToStringStyle} passed into the constructor.
088     * </p>
089     * 
090     * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
091     */
092    public class ReflectionToStringBuilder extends ToStringBuilder
093    {
094        /**
095         * <p>
096         * A registry of objects used by <code>reflectionToString</code> methods
097         * to detect cyclical object references and avoid infinite loops.
098         * </p>
099         */
100        private static ThreadLocal registry = new ThreadLocal()
101        {
102            protected synchronized Object initialValue()
103            {
104                // The HashSet implementation is not synchronized,
105                // which is just what we need here.
106                return new HashSet();
107            }
108        };
109    
110    
111        /**
112         * <p>
113         * Returns the registry of objects being traversed by the
114         * <code>reflectionToString</code> methods in the current thread.
115         * </p>
116         * 
117         * @return Set the registry of objects being traversed
118         */
119        static Set getRegistry()
120        {
121            return ( Set ) registry.get();
122        }
123    
124    
125        /**
126         * <p>
127         * Returns <code>true</code> if the registry contains the given object.
128         * Used by the reflection methods to avoid infinite loops.
129         * </p>
130         * 
131         * @param value
132         *            The object to lookup in the registry.
133         * @return boolean <code>true</code> if the registry contains the given
134         *         object.
135         */
136        static boolean isRegistered( Object value )
137        {
138            return getRegistry().contains( value );
139        }
140    
141    
142        /**
143         * <p>
144         * Registers the given object. Used by the reflection methods to avoid
145         * infinite loops.
146         * </p>
147         * 
148         * @param value
149         *            The object to register.
150         */
151        static void register( Object value )
152        {
153            getRegistry().add( value );
154        }
155    
156    
157        /**
158         * <p>
159         * This method uses reflection to build a suitable <code>toString</code>
160         * using the default <code>ToStringStyle</code>.
161         * <p>
162         * It uses <code>AccessibleObject.setAccessible</code> to gain access to
163         * private fields. This means that it will throw a security exception if run
164         * under a security manager, if the permissions are not set up correctly. It
165         * is also not as efficient as testing explicitly.
166         * </p>
167         * <p>
168         * Transient members will be not be included, as they are likely derived.
169         * Static fields will not be included. Superclass fields will be appended.
170         * </p>
171         * 
172         * @param object
173         *            the Object to be output
174         * @return the String result
175         * @throws IllegalArgumentException
176         *             if the Object is <code>null</code>
177         */
178        public static String toString( Object object )
179        {
180            return toString( object, null, false, false, null );
181        }
182    
183    
184        /**
185         * <p>
186         * This method uses reflection to build a suitable <code>toString</code>.
187         * </p>
188         * <p>
189         * It uses <code>AccessibleObject.setAccessible</code> to gain access to
190         * private fields. This means that it will throw a security exception if run
191         * under a security manager, if the permissions are not set up correctly. It
192         * is also not as efficient as testing explicitly.
193         * </p>
194         * <p>
195         * Transient members will be not be included, as they are likely derived.
196         * Static fields will not be included. Superclass fields will be appended.
197         * </p>
198         * <p>
199         * If the style is <code>null</code>, the default
200         * <code>ToStringStyle</code> is used.
201         * </p>
202         * 
203         * @param object
204         *            the Object to be output
205         * @param style
206         *            the style of the <code>toString</code> to create, may be
207         *            <code>null</code>
208         * @return the String result
209         * @throws IllegalArgumentException
210         *             if the Object or <code>ToStringStyle</code> is
211         *             <code>null</code>
212         */
213        public static String toString( Object object, ToStringStyle style )
214        {
215            return toString( object, style, false, false, null );
216        }
217    
218    
219        /**
220         * <p>
221         * This method uses reflection to build a suitable <code>toString</code>.
222         * </p>
223         * <p>
224         * It uses <code>AccessibleObject.setAccessible</code> to gain access to
225         * private fields. This means that it will throw a security exception if run
226         * under a security manager, if the permissions are not set up correctly. It
227         * is also not as efficient as testing explicitly.
228         * </p>
229         * <p>
230         * If the <code>outputTransients</code> is <code>true</code>, transient
231         * members will be output, otherwise they are ignored, as they are likely
232         * derived fields, and not part of the value of the Object.
233         * </p>
234         * <p>
235         * Static fields will not be included. Superclass fields will be appended.
236         * </p>
237         * <p>
238         * If the style is <code>null</code>, the default
239         * <code>ToStringStyle</code> is used.
240         * </p>
241         * 
242         * @param object
243         *            the Object to be output
244         * @param style
245         *            the style of the <code>toString</code> to create, may be
246         *            <code>null</code>
247         * @param outputTransients
248         *            whether to include transient fields
249         * @return the String result
250         * @throws IllegalArgumentException
251         *             if the Object is <code>null</code>
252         */
253        public static String toString( Object object, ToStringStyle style, boolean outputTransients )
254        {
255            return toString( object, style, outputTransients, false, null );
256        }
257    
258    
259        /**
260         * <p>
261         * This method uses reflection to build a suitable <code>toString</code>.
262         * </p>
263         * <p>
264         * It uses <code>AccessibleObject.setAccessible</code> to gain access to
265         * private fields. This means that it will throw a security exception if run
266         * under a security manager, if the permissions are not set up correctly. It
267         * is also not as efficient as testing explicitly.
268         * </p>
269         * <p>
270         * If the <code>outputTransients</code> is <code>true</code>, transient
271         * fields will be output, otherwise they are ignored, as they are likely
272         * derived fields, and not part of the value of the Object.
273         * </p>
274         * <p>
275         * If the <code>outputStatics</code> is <code>true</code>, static
276         * fields will be output, otherwise they are ignored.
277         * </p>
278         * <p>
279         * Static fields will not be included. Superclass fields will be appended.
280         * </p>
281         * <p>
282         * If the style is <code>null</code>, the default
283         * <code>ToStringStyle</code> is used.
284         * </p>
285         * 
286         * @param object
287         *            the Object to be output
288         * @param style
289         *            the style of the <code>toString</code> to create, may be
290         *            <code>null</code>
291         * @param outputTransients
292         *            whether to include transient fields
293         * @param outputStatics
294         *            whether to include transient fields
295         * @return the String result
296         * @throws IllegalArgumentException
297         *             if the Object is <code>null</code>
298         */
299        public static String toString( Object object, ToStringStyle style, boolean outputTransients, boolean outputStatics )
300        {
301            return toString( object, style, outputTransients, outputStatics, null );
302        }
303    
304    
305        /**
306         * <p>
307         * This method uses reflection to build a suitable <code>toString</code>.
308         * </p>
309         * <p>
310         * It uses <code>AccessibleObject.setAccessible</code> to gain access to
311         * private fields. This means that it will throw a security exception if run
312         * under a security manager, if the permissions are not set up correctly. It
313         * is also not as efficient as testing explicitly.
314         * </p>
315         * <p>
316         * If the <code>outputTransients</code> is <code>true</code>, transient
317         * fields will be output, otherwise they are ignored, as they are likely
318         * derived fields, and not part of the value of the Object.
319         * </p>
320         * <p>
321         * If the <code>outputStatics</code> is <code>true</code>, static
322         * fields will be output, otherwise they are ignored.
323         * </p>
324         * <p>
325         * Superclass fields will be appended up to and including the specified
326         * superclass. A null superclass is treated as <code>java.lang.Object</code>.
327         * </p>
328         * <p>
329         * If the style is <code>null</code>, the default
330         * <code>ToStringStyle</code> is used.
331         * </p>
332         * 
333         * @param object
334         *            the Object to be output
335         * @param style
336         *            the style of the <code>toString</code> to create, may be
337         *            <code>null</code>
338         * @param outputTransients
339         *            whether to include transient fields
340         * @param outputStatics
341         *            whether to include static fields
342         * @param reflectUpToClass
343         *            the superclass to reflect up to (inclusive), may be
344         *            <code>null</code>
345         * @return the String result
346         * @throws IllegalArgumentException
347         *             if the Object is <code>null</code>
348         */
349        public static String toString( Object object, ToStringStyle style, boolean outputTransients, boolean outputStatics,
350            Class reflectUpToClass )
351        {
352            return new ReflectionToStringBuilder( object, style, null, reflectUpToClass, outputTransients, outputStatics )
353                .toString();
354        }
355    
356    
357        /**
358         * <p>
359         * This method uses reflection to build a suitable <code>toString</code>.
360         * </p>
361         * <p>
362         * It uses <code>AccessibleObject.setAccessible</code> to gain access to
363         * private fields. This means that it will throw a security exception if run
364         * under a security manager, if the permissions are not set up correctly. It
365         * is also not as efficient as testing explicitly.
366         * </p>
367         * <p>
368         * If the <code>outputTransients</code> is <code>true</code>, transient
369         * members will be output, otherwise they are ignored, as they are likely
370         * derived fields, and not part of the value of the Object.
371         * </p>
372         * <p>
373         * Static fields will not be included. Superclass fields will be appended up
374         * to and including the specified superclass. A null superclass is treated
375         * as <code>java.lang.Object</code>.
376         * </p>
377         * <p>
378         * If the style is <code>null</code>, the default
379         * <code>ToStringStyle</code> is used.
380         * </p>
381         * 
382         * @deprecated Use
383         *             {@link #toString(Object,ToStringStyle,boolean,boolean,Class)}
384         * @param object
385         *            the Object to be output
386         * @param style
387         *            the style of the <code>toString</code> to create, may be
388         *            <code>null</code>
389         * @param outputTransients
390         *            whether to include transient fields
391         * @param reflectUpToClass
392         *            the superclass to reflect up to (inclusive), may be
393         *            <code>null</code>
394         * @return the String result
395         * @throws IllegalArgumentException
396         *             if the Object is <code>null</code>
397         */
398        public static String toString( Object object, ToStringStyle style, boolean outputTransients, Class reflectUpToClass )
399        {
400            return new ReflectionToStringBuilder( object, style, null, reflectUpToClass, outputTransients ).toString();
401        }
402    
403    
404        /**
405         * <p>
406         * Unregisters the given object.
407         * </p>
408         * <p>
409         * Used by the reflection methods to avoid infinite loops.
410         * </p>
411         * 
412         * @param value
413         *            The object to unregister.
414         */
415        static void unregister( Object value )
416        {
417            getRegistry().remove( value );
418        }
419    
420        /**
421         * Whether or not to append static fields.
422         */
423        private boolean appendStatics = false;
424    
425        /**
426         * Whether or not to append transient fields.
427         */
428        private boolean appendTransients = false;
429    
430        /**
431         * The last super class to stop appending fields for.
432         */
433        private Class upToClass = null;
434    
435    
436        /**
437         * <p>
438         * Constructor.
439         * </p>
440         * <p>
441         * This constructor outputs using the default style set with
442         * <code>setDefaultStyle</code>.
443         * </p>
444         * 
445         * @param object
446         *            the Object to build a <code>toString</code> for, must not be
447         *            <code>null</code>
448         * @throws IllegalArgumentException
449         *             if the Object passed in is <code>null</code>
450         */
451        public ReflectionToStringBuilder(Object object)
452        {
453            super( object );
454        }
455    
456    
457        /**
458         * <p>
459         * Constructor.
460         * </p>
461         * <p>
462         * If the style is <code>null</code>, the default style is used.
463         * </p>
464         * 
465         * @param object
466         *            the Object to build a <code>toString</code> for, must not be
467         *            <code>null</code>
468         * @param style
469         *            the style of the <code>toString</code> to create, may be
470         *            <code>null</code>
471         * @throws IllegalArgumentException
472         *             if the Object passed in is <code>null</code>
473         */
474        public ReflectionToStringBuilder(Object object, ToStringStyle style)
475        {
476            super( object, style );
477        }
478    
479    
480        /**
481         * <p>
482         * Constructor.
483         * </p>
484         * <p>
485         * If the style is <code>null</code>, the default style is used.
486         * </p>
487         * <p>
488         * If the buffer is <code>null</code>, a new one is created.
489         * </p>
490         * 
491         * @param object
492         *            the Object to build a <code>toString</code> for
493         * @param style
494         *            the style of the <code>toString</code> to create, may be
495         *            <code>null</code>
496         * @param buffer
497         *            the <code>StringBuffer</code> to populate, may be
498         *            <code>null</code>
499         * @throws IllegalArgumentException
500         *             if the Object passed in is <code>null</code>
501         */
502        public ReflectionToStringBuilder(Object object, ToStringStyle style, StringBuffer buffer)
503        {
504            super( object, style, buffer );
505        }
506    
507    
508        /**
509         * Constructor.
510         * 
511         * @deprecated Use
512         *             {@link #ReflectionToStringBuilder(Object,ToStringStyle,StringBuffer,Class,boolean,boolean)}.
513         * @param object
514         *            the Object to build a <code>toString</code> for
515         * @param style
516         *            the style of the <code>toString</code> to create, may be
517         *            <code>null</code>
518         * @param buffer
519         *            the <code>StringBuffer</code> to populate, may be
520         *            <code>null</code>
521         * @param reflectUpToClass
522         *            the superclass to reflect up to (inclusive), may be
523         *            <code>null</code>
524         * @param outputTransients
525         *            whether to include transient fields
526         */
527        public ReflectionToStringBuilder(Object object, ToStringStyle style, StringBuffer buffer, Class reflectUpToClass,
528            boolean outputTransients)
529        {
530            super( object, style, buffer );
531            this.setUpToClass( reflectUpToClass );
532            this.setAppendTransients( outputTransients );
533        }
534    
535    
536        /**
537         * Constructor.
538         * 
539         * @param object
540         *            the Object to build a <code>toString</code> for
541         * @param style
542         *            the style of the <code>toString</code> to create, may be
543         *            <code>null</code>
544         * @param buffer
545         *            the <code>StringBuffer</code> to populate, may be
546         *            <code>null</code>
547         * @param reflectUpToClass
548         *            the superclass to reflect up to (inclusive), may be
549         *            <code>null</code>
550         * @param outputTransients
551         *            whether to include transient fields
552         * @param outputStatics
553         *            whether to include static fields
554         */
555        public ReflectionToStringBuilder(Object object, ToStringStyle style, StringBuffer buffer, Class reflectUpToClass,
556            boolean outputTransients, boolean outputStatics)
557        {
558            super( object, style, buffer );
559            this.setUpToClass( reflectUpToClass );
560            this.setAppendTransients( outputTransients );
561            this.setAppendStatics( outputStatics );
562        }
563    
564    
565        /**
566         * Returns whether or not to append the given <code>Field</code>.
567         * <ul>
568         * <li>Transient fields are appended only if {@link #isAppendTransients()}
569         * returns <code>true</code>.
570         * <li>Static fields are appended only if {@link #isAppendStatics()}
571         * returns <code>true</code>.
572         * <li>Inner class fields are not appened.</li>
573         * </ul>
574         * 
575         * @param field
576         *            The Field to test.
577         * @return Whether or not to append the given <code>Field</code>.
578         */
579        protected boolean accept( Field field )
580        {
581            if ( field.getName().indexOf( '$' ) != -1 )
582            {
583                // Reject field from inner class.
584                return false;
585            }
586            if ( Modifier.isTransient( field.getModifiers() ) && !this.isAppendTransients() )
587            {
588                // transients.
589                return false;
590            }
591            if ( Modifier.isStatic( field.getModifiers() ) && !this.isAppendStatics() )
592            {
593                // transients.
594                return false;
595            }
596            return true;
597        }
598    
599    
600        /**
601         * <p>
602         * Appends the fields and values defined by the given object of the given
603         * Class.
604         * </p>
605         * <p>
606         * If a cycle is detected as an object is &quot;toString()'ed&quot;, such an
607         * object is rendered as if <code>Object.toString()</code> had been called
608         * and not implemented by the object.
609         * </p>
610         * 
611         * @param clazz
612         *            The class of object parameter
613         */
614        protected void appendFieldsIn( Class clazz )
615        {
616            if ( isRegistered( this.getObject() ) )
617            {
618                // The object has already been appended, therefore we have an
619                // object cycle.
620                // Append a simple Object.toString style string. The field name is
621                // already appended at this point.
622                this.appendAsObjectToString( this.getObject() );
623                return;
624            }
625            try
626            {
627                this.registerObject();
628                if ( clazz.isArray() )
629                {
630                    this.reflectionAppendArray( this.getObject() );
631                    return;
632                }
633                Field[] fields = clazz.getDeclaredFields();
634                AccessibleObject.setAccessible( fields, true );
635                for ( int i = 0; i < fields.length; i++ )
636                {
637                    Field field = fields[i];
638                    String fieldName = field.getName();
639                    if ( this.accept( field ) )
640                    {
641                        try
642                        {
643                            // Warning: Field.get(Object) creates wrappers objects
644                            // for primitive types.
645                            Object fieldValue = this.getValue( field );
646                            if ( isRegistered( fieldValue ) && !field.getType().isPrimitive() )
647                            {
648                                // A known field value has already been appended,
649                                // therefore we have an object cycle,
650                                // append a simple Object.toString style string.
651                                this.getStyle().appendFieldStart( this.getStringBuffer(), fieldName );
652                                this.appendAsObjectToString( fieldValue );
653                                // The recursion out of
654                                // builder.append(fieldName, fieldValue);
655                                // below will append the field
656                                // end marker.
657                            }
658                            else
659                            {
660                                try
661                                {
662                                    this.registerObject();
663                                    this.append( fieldName, fieldValue );
664                                }
665                                finally
666                                {
667                                    this.unregisterObject();
668                                }
669                            }
670                        }
671                        catch ( IllegalAccessException ex )
672                        {
673                            // this can't happen. Would get a Security exception
674                            // instead
675                            // throw a runtime exception in case the impossible
676                            // happens.
677                            throw new InternalError( "Unexpected IllegalAccessException: " + ex.getMessage() );
678                        }
679                    }
680                }
681            }
682            finally
683            {
684                this.unregisterObject();
685            }
686        }
687    
688    
689        /**
690         * <p>
691         * Gets the last super class to stop appending fields for.
692         * </p>
693         * 
694         * @return The last super class to stop appending fields for.
695         */
696        public Class getUpToClass()
697        {
698            return this.upToClass;
699        }
700    
701    
702        /**
703         * <p>
704         * Calls <code>java.lang.reflect.Field.get(Object)</code>.
705         * </p>
706         * 
707         * @param field
708         *            The Field to query.
709         * @return The Object from the given Field.
710         * @throws IllegalArgumentException
711         *             see {@link java.lang.reflect.Field#get(Object)}
712         * @throws IllegalAccessException
713         *             see {@link java.lang.reflect.Field#get(Object)}
714         * @see java.lang.reflect.Field#get(Object)
715         */
716        protected Object getValue( Field field ) throws IllegalArgumentException, IllegalAccessException
717        {
718            return field.get( this.getObject() );
719        }
720    
721    
722        /**
723         * <p>
724         * Gets whether or not to append static fields.
725         * </p>
726         * 
727         * @return Whether or not to append static fields.
728         */
729        public boolean isAppendStatics()
730        {
731            return this.appendStatics;
732        }
733    
734    
735        /**
736         * <p>
737         * Gets whether or not to append transient fields.
738         * </p>
739         * 
740         * @return Whether or not to append transient fields.
741         */
742        public boolean isAppendTransients()
743        {
744            return this.appendTransients;
745        }
746    
747    
748        /**
749         * <p>
750         * Append to the <code>toString</code> an <code>Object</code> array.
751         * </p>
752         * 
753         * @param array
754         *            the array to add to the <code>toString</code>
755         * @return this
756         */
757        public ToStringBuilder reflectionAppendArray( Object array )
758        {
759            this.getStyle().reflectionAppendArrayDetail( this.getStringBuffer(), null, array );
760            return this;
761        }
762    
763    
764        /**
765         * <p>
766         * Registers this builder's source object to avoid infinite loops when
767         * processing circular object references.
768         * </p>
769         */
770        void registerObject()
771        {
772            register( this.getObject() );
773        }
774    
775    
776        /**
777         * <p>
778         * Sets whether or not to append static fields.
779         * </p>
780         * 
781         * @param appendStatics
782         *            Whether or not to append static fields.
783         */
784        public void setAppendStatics( boolean appendStatics )
785        {
786            this.appendStatics = appendStatics;
787        }
788    
789    
790        /**
791         * <p>
792         * Sets whether or not to append transient fields.
793         * </p>
794         * 
795         * @param appendTransients
796         *            Whether or not to append transient fields.
797         */
798        public void setAppendTransients( boolean appendTransients )
799        {
800            this.appendTransients = appendTransients;
801        }
802    
803    
804        /**
805         * <p>
806         * Sets the last super class to stop appending fields for.
807         * </p>
808         * 
809         * @param clazz
810         *            The last super class to stop appending fields for.
811         */
812        public void setUpToClass( Class clazz )
813        {
814            this.upToClass = clazz;
815        }
816    
817    
818        /**
819         * <p>
820         * Gets the String built by this builder.
821         * </p>
822         * 
823         * @return the built string
824         */
825        public String toString()
826        {
827            if ( this.getObject() == null )
828            {
829                return this.getStyle().getNullText();
830            }
831            Class clazz = this.getObject().getClass();
832            this.appendFieldsIn( clazz );
833            while ( clazz.getSuperclass() != null && clazz != this.getUpToClass() )
834            {
835                clazz = clazz.getSuperclass();
836                this.appendFieldsIn( clazz );
837            }
838            return super.toString();
839        }
840    
841    
842        /**
843         * <p>
844         * Unregisters this builder's source object to avoid infinite loops when
845         * processing circular object references.
846         * </p>
847         */
848        void unregisterObject()
849        {
850            unregister( this.getObject() );
851        }
852    }