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