1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package net.sf.morph.transform.converters;
17
18 import java.util.Arrays;
19 import java.util.Locale;
20 import java.util.Set;
21
22 import net.sf.morph.transform.Converter;
23 import net.sf.morph.util.ClassUtils;
24 import net.sf.morph.util.ContainerUtils;
25 import net.sf.morph.util.MutableInteger;
26 import net.sf.morph.util.TransformerUtils;
27
28 /**.
29 * <p>
30 * Creates a String representation of an object that is useful for debugging.
31 * This class is threadsafe and will not enter an infinite loop, even if
32 * displaying the information in a cyclic graph of objects.
33 * </p>
34 *
35 * @author Matt Sgarlata
36 * @since Feb 15, 2005
37 */
38 public class ObjectToPrettyTextConverter extends BaseToPrettyTextConverter {
39 /** Default types using <code>toString()</code> */
40 public static final Class[] DEFAULT_TYPES_USING_TO_STRING = new Class[] {
41 String.class, Long.class, Integer.class, Short.class, Character.class,
42 Byte.class, Double.class, Float.class, Boolean.class, Long.TYPE,
43 Integer.TYPE, Short.TYPE, Character.TYPE, Byte.TYPE, Double.TYPE,
44 Float.TYPE, Boolean.TYPE, StringBuffer.class
45 };
46
47 /** Default levels */
48 public static final int DEFAULT_LEVELS = 1;
49
50 private int levels = DEFAULT_LEVELS;
51 private Converter containerToPrettyTextConverter;
52 private Converter beanToPrettyTextConverter;
53 private static ThreadLocal currentLevelThreadLocal = new ThreadLocal() {
54 /**
55 * {@inheritDoc}
56 */
57 protected Object initialValue() {
58 return new MutableInteger(-1);
59 }
60 };
61 private Set typesUsingToString;
62
63 /**
64 * Create a new ObjectToPrettyTextConverter.
65 */
66 public ObjectToPrettyTextConverter() {
67 super();
68 setTypesUsingToString(DEFAULT_TYPES_USING_TO_STRING);
69 }
70
71 /**
72 * {@inheritDoc}
73 */
74 protected Object convertImpl(Class destinationClass, Object source, Locale locale) throws Exception {
75 MutableInteger currentLevel = (MutableInteger) currentLevelThreadLocal.get();
76 currentLevel.value++;
77
78 try {
79
80 if (currentLevel.value < levels) {
81 if (source == null) {
82 return "null";
83 }
84 if (getTypesUsingToStringInternal().contains(source.getClass())) {
85 return source.toString();
86 }
87 if (TransformerUtils.isTransformable(getContainerToPrettyTextConverter(),
88 destinationClass, ClassUtils.getClass(source))) {
89 return getContainerToPrettyTextConverter().convert(destinationClass, source, locale);
90 }
91 if (TransformerUtils.isTransformable(getBeanToPrettyTextConverter(),
92 destinationClass, ClassUtils.getClass(source))) {
93 return getBeanToPrettyTextConverter().convert(destinationClass, source, locale);
94 }
95 }
96 }
97 catch (Exception e) {
98 if (log.isErrorEnabled()) {
99 log.error("Error occurred while attempting to create a formatted text representation of source " + source, e);
100 }
101 }
102 finally {
103 currentLevel.value--;
104 }
105 return getToTextConverter().convert(destinationClass, source, locale);
106 }
107
108 /**
109 * {@inheritDoc}
110 */
111 protected Class[] getSourceClassesImpl() throws Exception {
112 Set candidates = ContainerUtils.createOrderedSet();
113 candidates.addAll(Arrays.asList(getContainerToPrettyTextConverter().getSourceClasses()));
114 candidates.addAll(Arrays.asList(getBeanToPrettyTextConverter().getSourceClasses()));
115 candidates.addAll(Arrays.asList(getToTextConverter().getSourceClasses()));
116 return (Class[]) candidates.toArray(new Class[candidates.size()]);
117 }
118
119 /**
120 * Get the levels
121 * @return int
122 */
123 public int getLevels() {
124 return levels;
125 }
126
127 /**
128 * Set the levels.
129 * @param levels
130 */
131 public void setLevels(int levels) {
132 this.levels = levels;
133 }
134
135 /**
136 * Get the converter used to convert beans to pretty text.
137 * @return Converter
138 */
139 public Converter getBeanToPrettyTextConverter() {
140 if (beanToPrettyTextConverter == null) {
141 BeanToPrettyTextConverter converter = new BeanToPrettyTextConverter();
142 converter.setToTextConverter(this);
143 setBeanToPrettyTextConverter(converter);
144 }
145 return beanToPrettyTextConverter;
146 }
147
148 /**
149 * Set the converter used to convert beans to pretty text.
150 * @param beanToTextConverter
151 */
152 public void setBeanToPrettyTextConverter(Converter beanToTextConverter) {
153 this.beanToPrettyTextConverter = beanToTextConverter;
154 }
155
156 /**
157 * Get the converter used to convert containers to pretty text.
158 * @return Converter
159 */
160 public Converter getContainerToPrettyTextConverter() {
161 if (containerToPrettyTextConverter == null) {
162 ContainerToPrettyTextConverter converter = new ContainerToPrettyTextConverter();
163 converter.setToTextConverter(this);
164 setContainerToPrettyTextConverter(converter);
165 }
166 return containerToPrettyTextConverter;
167 }
168
169 /**
170 * Set the converter used to convert containers to pretty text.
171 * @param containerToTextConverter
172 */
173 public void setContainerToPrettyTextConverter(Converter containerToTextConverter) {
174 this.containerToPrettyTextConverter = containerToTextConverter;
175 }
176
177 /**
178 * Get the types using <code>toString()</code>.
179 * @return Set<Class>
180 */
181 protected Set getTypesUsingToStringInternal() {
182
183 if (typesUsingToString == null) getTypesUsingToString();
184 return typesUsingToString;
185 }
186
187 /**
188 * Get the types using <code>toString()</code>.
189 * @return Class[]
190 */
191 public Class[] getTypesUsingToString() {
192 if (typesUsingToString == null) {
193 setTypesUsingToString(DEFAULT_TYPES_USING_TO_STRING);
194 }
195 return (Class[]) typesUsingToString.toArray(new Class[typesUsingToString.size()]);
196 }
197
198 /**
199 * Set the types using <code>toString()</code>.
200 * @param typesUsingToString
201 */
202 public void setTypesUsingToString(Class[] typesUsingToString) {
203 Set s = ContainerUtils.createOrderedSet();
204 s.addAll(Arrays.asList(typesUsingToString));
205 this.typesUsingToString = s;
206 }
207 }