1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.beanutils.converters;
18
19 import java.lang.reflect.Array;
20 import java.util.Collection;
21 import org.apache.commons.logging.Log;
22 import org.apache.commons.logging.LogFactory;
23 import org.apache.commons.beanutils.BeanUtils;
24 import org.apache.commons.beanutils.ConversionException;
25 import org.apache.commons.beanutils.Converter;
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50 public abstract class AbstractConverter implements Converter {
51
52
53 private static final String DEFAULT_CONFIG_MSG =
54 "(N.B. Converters can be configured to use default values to avoid throwing exceptions)";
55
56
57
58
59 private static final String PACKAGE = "org.apache.commons.beanutils.converters.";
60
61
62
63
64 private transient Log log;
65
66
67
68
69 private boolean useDefault = false;
70
71
72
73
74 private Object defaultValue = null;
75
76
77
78
79
80
81
82 public AbstractConverter() {
83 }
84
85
86
87
88
89
90
91
92
93 public AbstractConverter(Object defaultValue) {
94 setDefaultValue(defaultValue);
95 }
96
97
98
99
100
101
102
103
104
105
106
107 public boolean isUseDefault() {
108 return useDefault;
109 }
110
111
112
113
114
115
116
117
118
119
120
121 public Object convert(Class type, Object value) {
122
123 Class sourceType = value == null ? null : value.getClass();
124 Class targetType = primitive(type == null ? getDefaultType() : type);
125
126 if (log().isDebugEnabled()) {
127 log().debug("Converting"
128 + (value == null ? "" : " '" + toString(sourceType) + "'")
129 + " value '" + value + "' to type '" + toString(targetType) + "'");
130 }
131
132 value = convertArray(value);
133
134
135 if (value == null) {
136 return handleMissing(targetType);
137 }
138
139 sourceType = value.getClass();
140
141 try {
142
143 if (targetType.equals(String.class)) {
144 return convertToString(value);
145
146
147 } else if (targetType.equals(sourceType)) {
148 if (log().isDebugEnabled()) {
149 log().debug(" No conversion required, value is already a "
150 + toString(targetType));
151 }
152 return value;
153
154
155 } else {
156 Object result = convertToType(targetType, value);
157 if (log().isDebugEnabled()) {
158 log().debug(" Converted to " + toString(targetType) +
159 " value '" + result + "'");
160 }
161 return result;
162 }
163 } catch (Throwable t) {
164 return handleError(targetType, value, t);
165 }
166
167 }
168
169
170
171
172
173
174
175
176
177
178
179
180
181 protected String convertToString(Object value) throws Throwable {
182 return value.toString();
183 }
184
185
186
187
188
189
190
191
192
193
194
195
196
197 protected abstract Object convertToType(Class type, Object value) throws Throwable;
198
199
200
201
202
203
204
205
206
207
208
209 protected Object convertArray(Object value) {
210 if (value == null) {
211 return null;
212 }
213 if (value.getClass().isArray()) {
214 if (Array.getLength(value) > 0) {
215 return Array.get(value, 0);
216 } else {
217 return null;
218 }
219 }
220 if (value instanceof Collection) {
221 Collection collection = (Collection)value;
222 if (collection.size() > 0) {
223 return collection.iterator().next();
224 } else {
225 return null;
226 }
227 }
228 return value;
229 }
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244 protected Object handleError(Class type, Object value, Throwable cause) {
245 if (log().isDebugEnabled()) {
246 if (cause instanceof ConversionException) {
247 log().debug(" Conversion threw ConversionException: " + cause.getMessage());
248 } else {
249 log().debug(" Conversion threw " + cause);
250 }
251 }
252
253 if (useDefault) {
254 return handleMissing(type);
255 }
256
257 ConversionException cex = null;
258 if (cause instanceof ConversionException) {
259 cex = (ConversionException)cause;
260 if (log().isDebugEnabled()) {
261 log().debug(" Re-throwing ConversionException: " + cex.getMessage());
262 log().debug(" " + DEFAULT_CONFIG_MSG);
263 }
264 } else {
265 String msg = "Error converting from '" + toString(value.getClass()) +
266 "' to '" + toString(type) + "' " + cause.getMessage();
267 cex = new ConversionException(msg, cause);
268 if (log().isDebugEnabled()) {
269 log().debug(" Throwing ConversionException: " + msg);
270 log().debug(" " + DEFAULT_CONFIG_MSG);
271 }
272 BeanUtils.initCause(cex, cause);
273 }
274
275 throw cex;
276
277 }
278
279
280
281
282
283
284
285
286
287
288
289
290 protected Object handleMissing(Class type) {
291
292 if (useDefault || type.equals(String.class)) {
293 Object value = getDefault(type);
294 if (useDefault && value != null && !(type.equals(value.getClass()))) {
295 try {
296 value = convertToType(type, defaultValue);
297 } catch (Throwable t) {
298 log().error(" Default conversion to " + toString(type)
299 + "failed: " + t);
300 }
301 }
302 if (log().isDebugEnabled()) {
303 log().debug(" Using default "
304 + (value == null ? "" : toString(value.getClass()) + " ")
305 + "value '" + defaultValue + "'");
306 }
307 return value;
308 }
309
310 ConversionException cex = new ConversionException("No value specified for '" +
311 toString(type) + "'");
312 if (log().isDebugEnabled()) {
313 log().debug(" Throwing ConversionException: " + cex.getMessage());
314 log().debug(" " + DEFAULT_CONFIG_MSG);
315 }
316 throw cex;
317
318 }
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333 protected void setDefaultValue(Object defaultValue) {
334 useDefault = false;
335 if (log().isDebugEnabled()) {
336 log().debug("Setting default value: " + defaultValue);
337 }
338 if (defaultValue == null) {
339 this.defaultValue = null;
340 } else {
341 this.defaultValue = convert(getDefaultType(), defaultValue);
342 }
343 useDefault = true;
344 }
345
346
347
348
349
350
351 protected abstract Class getDefaultType();
352
353
354
355
356
357
358
359 protected Object getDefault(Class type) {
360 if (type.equals(String.class)) {
361 return null;
362 } else {
363 return defaultValue;
364 }
365 }
366
367
368
369
370
371
372 public String toString() {
373 return toString(getClass()) + "[UseDefault=" + useDefault + "]";
374 }
375
376
377
378
379
380
381
382
383
384
385
386
387
388 Log log() {
389 if (log == null) {
390 log = LogFactory.getLog(getClass());
391 }
392 return log;
393 }
394
395
396
397
398
399
400 Class primitive(Class type) {
401 if (type == null || !type.isPrimitive()) {
402 return type;
403 }
404
405 if (type == Integer.TYPE) {
406 return Integer.class;
407 } else if (type == Double.TYPE) {
408 return Double.class;
409 } else if (type == Long.TYPE) {
410 return Long.class;
411 } else if (type == Boolean.TYPE) {
412 return Boolean.class;
413 } else if (type == Float.TYPE) {
414 return Float.class;
415 } else if (type == Short.TYPE) {
416 return Short.class;
417 } else if (type == Byte.TYPE) {
418 return Byte.class;
419 } else if (type == Character.TYPE) {
420 return Character.class;
421 } else {
422 return type;
423 }
424 }
425
426
427
428
429
430
431 String toString(Class type) {
432 String typeName = null;
433 if (type == null) {
434 typeName = "null";
435 } else if (type.isArray()) {
436 Class elementType = type.getComponentType();
437 int count = 1;
438 while (elementType.isArray()) {
439 elementType = elementType .getComponentType();
440 count++;
441 }
442 typeName = elementType.getName();
443 for (int i = 0; i < count; i++) {
444 typeName += "[]";
445 }
446 } else {
447 typeName = type.getName();
448 }
449 if (typeName.startsWith("java.lang.") ||
450 typeName.startsWith("java.util.") ||
451 typeName.startsWith("java.math.")) {
452 typeName = typeName.substring("java.lang.".length());
453 } else if (typeName.startsWith(PACKAGE)) {
454 typeName = typeName.substring(PACKAGE.length());
455 }
456 return typeName;
457 }
458 }