1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.commons.jxpath.util;
19
20 import java.lang.reflect.Array;
21 import java.lang.reflect.Modifier;
22 import java.math.BigDecimal;
23 import java.math.BigInteger;
24 import java.util.ArrayList;
25 import java.util.Collection;
26 import java.util.Collections;
27 import java.util.HashSet;
28 import java.util.Iterator;
29 import java.util.List;
30 import java.util.Set;
31 import java.util.SortedSet;
32
33 import org.apache.commons.beanutils.ConvertUtils;
34 import org.apache.commons.beanutils.Converter;
35 import org.apache.commons.jxpath.JXPathInvalidAccessException;
36 import org.apache.commons.jxpath.JXPathTypeConversionException;
37 import org.apache.commons.jxpath.NodeSet;
38 import org.apache.commons.jxpath.Pointer;
39
40
41
42
43 public class BasicTypeConverter implements TypeConverter {
44
45
46
47
48 static final class ValuePointer implements Pointer {
49
50 private static final long serialVersionUID = -4817239482392206188L;
51 private final Object bean;
52
53
54
55
56
57
58 public ValuePointer(final Object object) {
59 this.bean = object;
60 }
61
62 @Override
63 public String asPath() {
64 if (bean == null) {
65 return "null()";
66 }
67 if (bean instanceof Number) {
68 String string = bean.toString();
69 if (string.endsWith(".0")) {
70 string = string.substring(0, string.length() - 2);
71 }
72 return string;
73 }
74 if (bean instanceof Boolean) {
75 return ((Boolean) bean).booleanValue() ? "true()" : "false()";
76 }
77 if (bean instanceof String) {
78 return "'" + bean + "'";
79 }
80 return "{object of type " + bean.getClass().getName() + "}";
81 }
82
83 @Override
84 public Object clone() {
85 return this;
86 }
87
88 @Override
89 public int compareTo(final Object object) {
90 return 0;
91 }
92
93 @Override
94 public Object getNode() {
95 return bean;
96 }
97
98 @Override
99 public Object getRootNode() {
100 return bean;
101 }
102
103 @Override
104 public Object getValue() {
105 return bean;
106 }
107
108 @Override
109 public void setValue(final Object value) {
110 throw new UnsupportedOperationException();
111 }
112 }
113
114
115
116
117
118 public BasicTypeConverter() {
119
120 }
121
122
123
124
125
126
127
128 protected Collection allocateCollection(final Class type) {
129 if (!type.isInterface() && (type.getModifiers() & Modifier.ABSTRACT) == 0) {
130 try {
131 return (Collection) type.getConstructor().newInstance();
132 } catch (final Exception ex) {
133 throw new JXPathInvalidAccessException("Cannot create collection of type: " + type, ex);
134 }
135 }
136 if (type == List.class || type == Collection.class) {
137 return new ArrayList();
138 }
139 if (type == Set.class) {
140 return new HashSet();
141 }
142 throw new JXPathInvalidAccessException("Cannot create collection of type: " + type);
143 }
144
145
146
147
148
149
150
151
152 protected Number allocateNumber(Class type, final double value) {
153 type = TypeUtils.wrapPrimitive(type);
154 if (type == Byte.class) {
155 return Byte.valueOf((byte) value);
156 }
157 if (type == Short.class) {
158 return Short.valueOf((short) value);
159 }
160 if (type == Integer.class) {
161 return Integer.valueOf((int) value);
162 }
163 if (type == Long.class) {
164 return Long.valueOf((long) value);
165 }
166 if (type == Float.class) {
167 return Float.valueOf((float) value);
168 }
169 if (type == Double.class) {
170 return Double.valueOf(value);
171 }
172 if (type == BigInteger.class) {
173 return BigInteger.valueOf((long) value);
174 }
175 if (type == BigDecimal.class) {
176 return new BigDecimal(Double.toString(value));
177 }
178 final String className = type.getName();
179 Class initialValueType = null;
180 if ("java.util.concurrent.atomic.AtomicInteger".equals(className)) {
181 initialValueType = int.class;
182 }
183 if ("java.util.concurrent.atomic.AtomicLong".equals(className)) {
184 initialValueType = long.class;
185 }
186 if (initialValueType != null) {
187 try {
188 return (Number) type.getConstructor(new Class[] { initialValueType }).newInstance(allocateNumber(initialValueType, value));
189 } catch (final Exception e) {
190 throw new JXPathTypeConversionException(className, e);
191 }
192 }
193 return null;
194 }
195
196
197
198
199
200
201
202
203 @Override
204 public boolean canConvert(final Object object, final Class toType) {
205 if (object == null) {
206 return true;
207 }
208 final Class useType = TypeUtils.wrapPrimitive(toType);
209 final Class fromType = object.getClass();
210 if (useType.isAssignableFrom(fromType)) {
211 return true;
212 }
213 if (useType == String.class) {
214 return true;
215 }
216 if (object instanceof Boolean && (Number.class.isAssignableFrom(useType) || "java.util.concurrent.atomic.AtomicBoolean".equals(useType.getName()))) {
217 return true;
218 }
219 if (object instanceof Number && (Number.class.isAssignableFrom(useType) || useType == Boolean.class)) {
220 return true;
221 }
222 if (object instanceof String && (useType == Boolean.class || useType == Character.class || useType == Byte.class || useType == Short.class
223 || useType == Integer.class || useType == Long.class || useType == Float.class || useType == Double.class)) {
224 return true;
225 }
226 if (fromType.isArray()) {
227
228 if (useType.isArray()) {
229 final Class cType = useType.getComponentType();
230 final int length = Array.getLength(object);
231 for (int i = 0; i < length; i++) {
232 final Object value = Array.get(object, i);
233 if (!canConvert(value, cType)) {
234 return false;
235 }
236 }
237 return true;
238 }
239 if (Collection.class.isAssignableFrom(useType)) {
240 return canCreateCollection(useType);
241 }
242 if (Array.getLength(object) > 0) {
243 final Object value = Array.get(object, 0);
244 return canConvert(value, useType);
245 }
246 return canConvert("", useType);
247 }
248 if (object instanceof Collection) {
249
250 if (useType.isArray()) {
251 final Class cType = useType.getComponentType();
252 final Iterator it = ((Collection) object).iterator();
253 while (it.hasNext()) {
254 final Object value = it.next();
255 if (!canConvert(value, cType)) {
256 return false;
257 }
258 }
259 return true;
260 }
261 if (Collection.class.isAssignableFrom(useType)) {
262 return canCreateCollection(useType);
263 }
264 if (((Collection) object).size() > 0) {
265 Object value;
266 if (object instanceof List) {
267 value = ((List) object).get(0);
268 } else {
269 final Iterator it = ((Collection) object).iterator();
270 value = it.next();
271 }
272 return canConvert(value, useType);
273 }
274 return canConvert("", useType);
275 }
276 if (object instanceof NodeSet) {
277 return canConvert(((NodeSet) object).getValues(), useType);
278 }
279 if (object instanceof Pointer) {
280 return canConvert(((Pointer) object).getValue(), useType);
281 }
282 return ConvertUtils.lookup(useType) != null;
283 }
284
285
286
287
288
289
290
291 protected boolean canCreateCollection(final Class type) {
292 if (!type.isInterface() && (type.getModifiers() & Modifier.ABSTRACT) == 0) {
293 try {
294 type.getConstructor();
295 return true;
296 } catch (final Exception e) {
297 return false;
298 }
299 }
300 return type == List.class || type == Collection.class || type == Set.class;
301 }
302
303
304
305
306
307
308
309
310 @Override
311 public Object convert(final Object object, final Class toType) {
312 if (object == null) {
313 return toType.isPrimitive() ? convertNullToPrimitive(toType) : null;
314 }
315 if (toType == Object.class) {
316 if (object instanceof NodeSet) {
317 return convert(((NodeSet) object).getValues(), toType);
318 }
319 if (object instanceof Pointer) {
320 return convert(((Pointer) object).getValue(), toType);
321 }
322 return object;
323 }
324 final Class useType = TypeUtils.wrapPrimitive(toType);
325 final Class fromType = object.getClass();
326 if (useType.isAssignableFrom(fromType)) {
327 return object;
328 }
329 if (fromType.isArray()) {
330 final int length = Array.getLength(object);
331 if (useType.isArray()) {
332 final Class cType = useType.getComponentType();
333 final Object array = Array.newInstance(cType, length);
334 for (int i = 0; i < length; i++) {
335 final Object value = Array.get(object, i);
336 Array.set(array, i, convert(value, cType));
337 }
338 return array;
339 }
340 if (Collection.class.isAssignableFrom(useType)) {
341 final Collection collection = allocateCollection(useType);
342 for (int i = 0; i < length; i++) {
343 collection.add(Array.get(object, i));
344 }
345 return unmodifiableCollection(collection);
346 }
347 if (length > 0) {
348 final Object value = Array.get(object, 0);
349 return convert(value, useType);
350 }
351 return convert("", useType);
352 }
353 if (object instanceof Collection) {
354 final int length = ((Collection) object).size();
355 if (useType.isArray()) {
356 final Class cType = useType.getComponentType();
357 final Object array = Array.newInstance(cType, length);
358 final Iterator it = ((Collection) object).iterator();
359 for (int i = 0; i < length; i++) {
360 final Object value = it.next();
361 Array.set(array, i, convert(value, cType));
362 }
363 return array;
364 }
365 if (Collection.class.isAssignableFrom(useType)) {
366 final Collection collection = allocateCollection(useType);
367 collection.addAll((Collection) object);
368 return unmodifiableCollection(collection);
369 }
370 if (length > 0) {
371 Object value;
372 if (object instanceof List) {
373 value = ((List) object).get(0);
374 } else {
375 final Iterator it = ((Collection) object).iterator();
376 value = it.next();
377 }
378 return convert(value, useType);
379 }
380 return convert("", useType);
381 }
382 if (object instanceof NodeSet) {
383 return convert(((NodeSet) object).getValues(), useType);
384 }
385 if (object instanceof Pointer) {
386 return convert(((Pointer) object).getValue(), useType);
387 }
388 if (useType == String.class) {
389 return object.toString();
390 }
391 if (object instanceof Boolean) {
392 if (Number.class.isAssignableFrom(useType)) {
393 return allocateNumber(useType, ((Boolean) object).booleanValue() ? 1 : 0);
394 }
395 if ("java.util.concurrent.atomic.AtomicBoolean".equals(useType.getName())) {
396 try {
397 return useType.getConstructor(new Class[] { boolean.class }).newInstance(object);
398 } catch (final Exception e) {
399 throw new JXPathTypeConversionException(useType.getName(), e);
400 }
401 }
402 }
403 if (object instanceof Number) {
404 final double value = ((Number) object).doubleValue();
405 if (useType == Boolean.class) {
406 return value == 0.0 ? Boolean.FALSE : Boolean.TRUE;
407 }
408 if (Number.class.isAssignableFrom(useType)) {
409 return allocateNumber(useType, value);
410 }
411 }
412 if (object instanceof String) {
413 final Object value = convertStringToPrimitive(object, useType);
414 if (value != null) {
415 return value;
416 }
417 }
418 final Converter converter = ConvertUtils.lookup(useType);
419 if (converter != null) {
420 return converter.convert(useType, object);
421 }
422 throw new JXPathTypeConversionException("Cannot convert " + object.getClass() + " to " + useType);
423 }
424
425
426
427
428
429
430
431 protected Object convertNullToPrimitive(final Class toType) {
432 if (toType == boolean.class) {
433 return Boolean.FALSE;
434 }
435 if (toType == char.class) {
436 return Character.valueOf('\0');
437 }
438 if (toType == byte.class) {
439 return Byte.valueOf((byte) 0);
440 }
441 if (toType == short.class) {
442 return Short.valueOf((short) 0);
443 }
444 if (toType == int.class) {
445 return Integer.valueOf(0);
446 }
447 if (toType == long.class) {
448 return Long.valueOf(0L);
449 }
450 if (toType == float.class) {
451 return Float.valueOf(0.0f);
452 }
453 if (toType == double.class) {
454 return Double.valueOf(0.0);
455 }
456 return null;
457 }
458
459
460
461
462
463
464
465
466 protected Object convertStringToPrimitive(final Object object, Class toType) {
467 toType = TypeUtils.wrapPrimitive(toType);
468 if (toType == Boolean.class) {
469 return Boolean.valueOf((String) object);
470 }
471 if (toType == Character.class) {
472 return Character.valueOf(((String) object).charAt(0));
473 }
474 if (toType == Byte.class) {
475 return Byte.valueOf((String) object);
476 }
477 if (toType == Short.class) {
478 return Short.valueOf((String) object);
479 }
480 if (toType == Integer.class) {
481 return Integer.valueOf((String) object);
482 }
483 if (toType == Long.class) {
484 return Long.valueOf((String) object);
485 }
486 if (toType == Float.class) {
487 return Float.valueOf((String) object);
488 }
489 if (toType == Double.class) {
490 return Double.valueOf((String) object);
491 }
492 return null;
493 }
494
495
496
497
498
499
500
501
502 protected <E> Collection<E> unmodifiableCollection(final Collection<E> collection) {
503 if (collection instanceof List) {
504 return Collections.unmodifiableList((List<E>) collection);
505 }
506 if (collection instanceof SortedSet) {
507 return Collections.unmodifiableSortedSet((SortedSet<E>) collection);
508 }
509 if (collection instanceof Set) {
510 return Collections.unmodifiableSet((Set<E>) collection);
511 }
512 return Collections.unmodifiableCollection(collection);
513 }
514 }