View Javadoc

1   /*
2    * Copyright 2004 Sun Microsystems, Inc.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   *
16   */
17  package com.sun.syndication.common;
18  
19  import java.beans.BeanInfo;
20  import java.beans.Introspector;
21  import java.beans.PropertyDescriptor;
22  import java.lang.reflect.Array;
23  import java.lang.reflect.Method;
24  import java.util.Collection;
25  import java.util.Iterator;
26  import java.util.Map;
27  import java.io.Serializable;
28  
29  /***
30   * Provides deep <b>Bean</b> toString support.
31   * <p>
32   * It works on all read/write properties, recursively. It support all primitive types, Strings, Collections,
33   * ToString objects and multi-dimensional arrays of any of them.
34   * <p>
35   * @author Alejandro Abdelnur
36   *
37   */
38  public class ToStringBean implements Serializable, ToString {
39  
40      private static final Object[] NO_PARAMS = new Object[0];
41  
42      private Class _beanClass;
43      private Object _obj;
44  
45      /***
46       * Default constructor.
47       * <p>
48       * To be used by classes extending ToStringBean only.
49       * <p>
50       * @param beanClass indicates the class to scan for properties, normally an interface class.
51       *
52       */
53      protected ToStringBean(Class beanClass) {
54          _beanClass = beanClass;
55          _obj = this;
56      }
57  
58      /***
59       * Creates a ToStringBean to be used in a delegation pattern.
60       * <p>
61       * For example:
62       * <p>
63       * <code>
64       *   public class Foo implements ToString {
65       *
66       *       public String toString(String prefix) {
67       *           ToStringBean tsb = new ToStringBean(this);
68       *           return tsb.toString(prefix);
69       *       }
70       *
71       *       public String toString() {
72       *           return toString("Foo");
73       *       }
74       *
75       *   }
76       * </code>
77       * <p>
78       * @param beanClass indicates the class to scan for properties, normally an interface class.
79       * @param obj object bean to create String representation.
80       *
81       */
82      public ToStringBean(Class beanClass,Object obj) {
83          _beanClass = beanClass;
84          _obj = obj;
85      }
86  
87      /***
88       * Returns the String representation of the bean given in the constructor.
89       * <p>
90       * It uses the Class name as the prefix.
91       * <p>
92       * @return bean object String representation.
93       *
94       */
95      public String toString() {
96          String className = _obj.getClass().getName();
97          className = className.substring(className.lastIndexOf(".")+1);
98          return toString(className);
99      }
100 
101     /***
102      * Returns the String representation of the bean given in the constructor.
103      * <p>
104      * @param prefix to use for bean properties.
105      * @return bean object String representation.
106      *
107      */
108     public String toString(String prefix) {
109         StringBuffer sb = new StringBuffer(128);
110         try {
111             BeanInfo bi = Introspector.getBeanInfo(_beanClass);
112             PropertyDescriptor[] pds = bi.getPropertyDescriptors();
113             if (pds!=null) {
114                 for (int i=0;i<pds.length;i++) {
115                     String pName = pds[i].getName();
116                     Method pReadMethod = pds[i].getReadMethod();
117                     if (pReadMethod!=null &&                             // ensure it has a getter method
118                         pReadMethod.getDeclaringClass()!=Object.class && // filter Object.class getter methods
119                         pReadMethod.getParameterTypes().length==0) {     // filter getter methods that take parameters
120                         Object value = pReadMethod.invoke(_obj,NO_PARAMS);
121                         printProperty(sb,prefix+"."+pName,value);
122                     }
123                 }
124             }
125         }
126         catch (Exception ex) {
127             sb.append("\n\nEXCEPTION: Could not complete ").append(_obj.getClass()).append(".toString()\n");
128         }
129         return sb.toString();
130     }
131 
132     private void printProperty(StringBuffer sb,String prefix,Object value) {
133         if (value==null) {
134             sb.append(prefix).append("=null\n");
135         }
136         else
137         if (value.getClass().isArray()) {
138             printArrayProperty(sb,prefix,value);
139         }
140         else
141         if (value instanceof ToString) {
142             ToString ts = (ToString) value;
143             sb.append(ts.toString(prefix));
144         }
145         else
146         if (value instanceof Map) {
147             Map map = (Map) value;
148             Iterator i = map.entrySet().iterator();
149             if (i.hasNext()) {
150                 while (i.hasNext()) {
151                     Map.Entry me = (Map.Entry) i.next();
152                     String ePrefix = prefix+"["+me.getKey()+"]";
153                     Object eValue = me.getValue();
154                     if (eValue instanceof ToString) {
155                         ToString ts = (ToString) eValue;
156                         sb.append(ts.toString(ePrefix));
157                     }
158                     else {
159                         sb.append(ePrefix).append("=").append(eValue).append("\n");
160                     }
161                 }
162             }
163             else {
164                 sb.append(prefix).append("=[]\n");
165             }
166         }
167         else
168         if (value instanceof Collection) {
169             Collection collection = (Collection) value;
170             Iterator i = collection.iterator();
171             if (i.hasNext()) {
172                 int c = 0;
173                 while (i.hasNext()) {
174                     String cPrefix = prefix+"["+(c++)+"]";
175                     Object cValue = i.next();
176                     if (cValue instanceof ToString) {
177                         ToString ts = (ToString) cValue;
178                         sb.append(ts.toString(cPrefix));
179                     }
180                     else {
181                         sb.append(cPrefix).append("=").append(cValue).append("\n");
182                     }
183                 }
184             }
185             else {
186                 sb.append(prefix).append("=[]\n");
187             }
188         }
189         else {
190             sb.append(prefix).append("=").append(value).append("\n");
191         }
192     }
193 
194     private void printArrayProperty(StringBuffer sb, String prefix,Object array) {
195         int length = Array.getLength(array);
196         for (int i=0;i<length;i++) {
197             Object obj = Array.get(array,i);
198             printProperty(sb,prefix+"["+i+"]",obj);
199         }
200     }
201 
202 }
203