1
2
3
4
5
6
7
8
9
10
11
12
13
14
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 &&
118 pReadMethod.getDeclaringClass()!=Object.class &&
119 pReadMethod.getParameterTypes().length==0) {
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