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