KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > inversoft > util > ObjectTools


1 /*
2  * Copyright (c) 2003, Inversoft
3  *
4  * This software is distribuable under the GNU Lesser General Public License.
5  * For more information visit gnu.org.
6  */

7 package com.inversoft.util;
8
9
10 import java.lang.reflect.Array JavaDoc;
11 import java.util.Arrays JavaDoc;
12 import java.util.Collection JavaDoc;
13 import java.util.Iterator JavaDoc;
14 import java.util.List JavaDoc;
15 import java.util.Map JavaDoc;
16
17
18 /**
19  * This class is a toolkit that contains methods that help
20  * when dealing with objects. It is similar to the {@link
21  * StringTools StringTools} class of this package.
22  *
23  * @author Brian Pontarelli
24  * @since 1.0
25  * @version 2.0
26  */

27 public class ObjectTools {
28
29     /**
30      * Converts the given Object cleanly to a String. If the Object is null, the
31      * String is empty. Else, it returns the value of the toString method
32      *
33      * @param obj The Object to convert to a String
34      * @return The String value and never null
35      */

36     public static String JavaDoc cleanToString(Object JavaDoc obj) {
37
38         if (obj == null) {
39             return "";
40         }
41
42         return obj.toString();
43     }
44
45     /**
46      * Converts the given Object to a String. If the Object is null, the String
47      * is null. Else, it returns the value of the toString method
48      *
49      * @param obj The Object to convert to a String
50      * @return The String value or null if the object is null
51      */

52     public static String JavaDoc toString(Object JavaDoc obj) {
53         return (obj == null) ? null : obj.toString();
54     }
55
56     /**
57      * Compares the two objects for equality. This comparison is done at the reference
58      * level and the object level. If either object is null and the other is not,
59      * this method returns false. If both objects are null, this method returns true.
60      * If both objects are not null, the result is determined as follows:<br>
61      * If obj1 is a String {@link #areObjectsEqual(String, Object) areObjectsEqual(
62      * String, Object)} is called with (obj1, obj2)<br>
63      * If obj2 is a String {@link #areObjectsEqual(String, Object) areObjectsEqual(
64      * String, Object)} is called with (obj2, obj1)<br>
65      * If obj1 is an array and obj2 is not, obj1 is searched for an element that is
66      * equal to obj2 using the equals method<br>
67      * If obj2 is an array and obj1 is not, obj2 is searched for an element that is
68      * equal to obj1 using the equals method<br>
69      * If obj1 is an array and obj2 is an array, all the elements in the arrays must
70      * be equal using the equals method<br>
71      * The above array rules are repeated for Collection objects<br>
72      * If one is an array and the other a collection, all the elements in the array
73      * and the collection must be equal using the equals method<br>
74      * If they are both simple objects, they are compared using the equals method<br>
75      * It should also be noted that no matter what comparison is being done, null values
76      * are checked for. For example, if they both are arrays, then if array1[2] == null
77      * and array2[2] == null, then the array elements are considered equal
78      *
79      * @param obj1 The first object to be compared
80      * @param obj2 The second object to be compared
81      * @return True if the two parameters are equal using the above criteria
82      */

83     public static boolean areObjectsEqual(Object JavaDoc obj1, Object JavaDoc obj2) {
84
85         // If they are equal (like both null) return true
86
if (obj1 == obj2) {
87             return true;
88         }
89
90         // Since they are both not null, if one is, return false
91
if (obj1 == null || obj2 == null) {
92             return false;
93         }
94
95         // Forward handling to the other method if one is a string
96
if (obj1 instanceof String JavaDoc) {
97             return areObjectsEqual((String JavaDoc) obj1, obj2);
98         } else if (obj2 instanceof String JavaDoc) {
99             return areObjectsEqual((String JavaDoc) obj2, obj1);
100         }
101
102         boolean is1Array = obj1.getClass().isArray();
103         boolean is2Array = obj2.getClass().isArray();
104         boolean is1Collection = (obj1 instanceof Collection JavaDoc);
105         boolean is2Collection = (obj2 instanceof Collection JavaDoc);
106
107         if (is1Array && is2Array) {
108             return Arrays.equals((Object JavaDoc []) obj1, (Object JavaDoc []) obj2);
109         } else if (is1Array && is2Collection) {
110             return Arrays.equals((Object JavaDoc []) obj1, ((Collection JavaDoc) obj2).toArray());
111         } else if (is2Array && is1Collection) {
112             return Arrays.equals(((Collection JavaDoc) obj1).toArray(), (Object JavaDoc []) obj2);
113         } else if (is1Array) {
114             return arrayContains((Object JavaDoc []) obj1, obj2);
115         } else if (is2Array) {
116             return arrayContains((Object JavaDoc []) obj2, obj1);
117         } else if (is1Collection && is2Collection) {
118             return ((Collection JavaDoc) obj1).containsAll( (Collection JavaDoc) obj2 );
119         } else if (is1Collection) {
120             return ((Collection JavaDoc) obj1).contains(obj2);
121         } else if (is2Collection) {
122             return ((Collection JavaDoc) obj2).contains(obj1);
123         }
124
125         return obj1.equals(obj2);
126     }
127
128     /**
129      * Compares the the String and the object for equality. This comparison is done
130      * at the reference level and the object level. If either object is null and the
131      * other is not, this method returns false. If both objects are null, this method
132      * returns true. If both objects are not null, the result is determined as follows:
133      * <br>
134      * If obj2 is an array, the array is checked for an element whose toString value
135      * is equal to the String<br>
136      * If obj2 is a Collection, the Collection is checked for an element whose toString
137      * value is equal to the String<br>
138      * If obj2 is a simple Object, it's toString value is compared to the String<br>
139      * It should also be noted that no matter what comparison is being done, null values
140      * are checked for. For example, if obj2 is an array, then if obj2[2] == null
141      * and String == null, then the object is considered equal
142      *
143      * @param string The String to compare
144      * @param obj The object to compare
145      * @return True if the two parameters are equal using the above criteria
146      */

147     public static boolean areObjectsEqual(String JavaDoc string, Object JavaDoc obj) {
148
149         if (string == obj) {
150             return true;
151         }
152
153         if (string == null || obj == null) {
154             return false;
155         }
156
157         if (obj instanceof Object JavaDoc []) {
158             return arrayContainsString((Object JavaDoc []) obj, string);
159         } else if (obj instanceof Collection JavaDoc) {
160             return arrayContainsString(((Collection JavaDoc) obj).toArray(), string);
161         }
162
163         return string.equals(obj.toString());
164     }
165
166     /**
167      * Determines whether the specified array contains the specified objcet. This
168      * is done as follows:<br>
169      * If the obj is a string, the {@link #arrayContainsString(Object[], String)
170      * arrayContainsString(Object[], String)} method is called<br>
171      * Otherwise, each array position is compared to the object using the equals
172      * method
173      *
174      * @param array The array to search
175      * @param obj The object to search for
176      * @return True if the array contains the object, false otherwise
177      */

178     public static boolean arrayContains(Object JavaDoc [] array, Object JavaDoc obj) {
179
180         if (array == obj) {
181             return true;
182         }
183
184         if (array == null || obj == null) {
185             return false;
186         }
187
188         if (obj instanceof String JavaDoc) {
189             return arrayContainsString(array, (String JavaDoc) obj);
190         }
191
192         for (int i = 0; i < array.length; i++) {
193
194             if (array[i] != null && areObjectsEqual(array[i], obj)) {
195                 return true;
196             }
197         }
198
199         return false;
200     }
201
202     /**
203      * Determines whether the specified array contains the specified String. This
204      * is done as follows:<br>
205      * Each array position is compared to the String by converting it to a String
206      * using the toString method and then comparing it to the given String
207      *
208      * @param array The array to search
209      * @param string The String to search for
210      * @return True if the array contains the String, false otherwise
211      */

212     public static boolean arrayContainsString(Object JavaDoc [] array, String JavaDoc string) {
213
214         if (array == null && string == null) {
215             return true;
216         }
217
218         if (array == null || string == null) {
219             return false;
220         }
221
222         for (int i = 0; i < array.length; i++) {
223
224             if (array[i] != null && string.equals(array[i].toString())) {
225                 return true;
226             }
227         }
228
229         return false;
230     }
231
232     /**
233      * Given the array of primitive types given, this wraps each object and
234      * returns them in an array of Number objects.
235      *
236      * @param array The array of primitive types
237      * @return An array of Number objects or null
238      */

239     public static Number JavaDoc[] wrapArray(Object JavaDoc array) {
240         Number JavaDoc[] numbers = null;
241         if (array instanceof byte[]) {
242             byte[] bytes = (byte[]) array;
243             numbers = new Byte JavaDoc[bytes.length];
244             for (int i = 0; i < bytes.length; i++) {
245                 numbers[i] = new Byte JavaDoc(bytes[i]);
246             }
247         } else if (array instanceof double[]) {
248             double[] doubles = (double[]) array;
249             numbers = new Double JavaDoc[doubles.length];
250             for (int i = 0; i < doubles.length; i++) {
251                 numbers[i] = new Double JavaDoc(doubles[i]);
252             }
253         } else if (array instanceof float[]) {
254             float[] floats = (float[]) array;
255             numbers = new Float JavaDoc[floats.length];
256             for (int i = 0; i < floats.length; i++) {
257                 numbers[i] = new Float JavaDoc(floats[i]);
258             }
259         } else if (array instanceof int[]) {
260             int[] ints = (int[]) array;
261             numbers = new Integer JavaDoc[ints.length];
262             for (int i = 0; i < ints.length; i++) {
263                 numbers[i] = new Integer JavaDoc(ints[i]);
264             }
265         } else if (array instanceof long[]) {
266             long[] longs = (long[]) array;
267             numbers = new Long JavaDoc[longs.length];
268             for (int i = 0; i < longs.length; i++) {
269                 numbers[i] = new Long JavaDoc(longs[i]);
270             }
271         } else if (array instanceof short[]) {
272             short[] shorts = (short[]) array;
273             numbers = new Short JavaDoc[shorts.length];
274             for (int i = 0; i < shorts.length; i++) {
275                 numbers[i] = new Short JavaDoc(shorts[i]);
276             }
277         }
278
279         return numbers;
280     }
281
282     /**
283      * Using the data structure (ie Collection or Map instance) and key given,
284      * this retrieves the value from the data structure and returns it. If the
285      * data structure is a Map, this uses the key as is. Otherwise this verifies
286      * that the key is an Integer and then uses the intValue of that for the indices
287      * into the List, Collection or array.
288      *
289      * @param dataStructure The data structure instance to retrieve the value from
290      * @param key The indices/key to use to retrieve the value
291      * @return The value or null
292      * @throws IllegalArgumentException If the key is the wrong type for the
293      * Collection type or the dataStructure is not a List, Map,
294      * Collection or array
295      * @throws IndexOutOfBoundsException If the dataStructure is a List, Collection
296      * or an array and the index value is out of bounds
297      */

298     public static Object JavaDoc getValueFromCollection(final Object JavaDoc dataStructure,
299             final Object JavaDoc key) {
300         Object JavaDoc value = null;
301
302         // Figure out what type the property is and handle it accordingly
303
if (dataStructure instanceof Map JavaDoc) {
304             value = ((Map JavaDoc) dataStructure).get(key);
305         } else {
306             Class JavaDoc type = dataStructure.getClass();
307             boolean isList = (List JavaDoc.class.isAssignableFrom(type));
308             boolean isCollection = (Collection JavaDoc.class.isAssignableFrom(type));
309             boolean isArray = (type.isArray());
310
311             if (!isList && !isArray && !isCollection) {
312                 throw new IllegalArgumentException JavaDoc("Invalid data structure type: " +
313                     type.getName());
314             }
315
316             int index = -1;
317             try {
318                 index = ((Integer JavaDoc) key).intValue();
319             } catch (ClassCastException JavaDoc cce) {
320                 throw new IllegalArgumentException JavaDoc("Invalid indices/key: " + key +
321                     " for data strucutre of type " + type.getName());
322             }
323
324             if (isList) {
325                 value = ((List JavaDoc) dataStructure).get(index);
326             } else if (isCollection) {
327
328                 // Iterator over the collection and retrieve the value
329
Iterator JavaDoc iter = ((Collection JavaDoc) dataStructure).iterator();
330                 for (int i = 0; i < index && iter.hasNext(); i++) {
331                     iter.next();
332                 }
333
334                 if (iter.hasNext()) {
335                     value = iter.next();
336                 } else {
337                     throw new IndexOutOfBoundsException JavaDoc("Index of out bounds: " +
338                         index);
339                 }
340             } else if (isArray) {
341                 value = ((Object JavaDoc[]) dataStructure)[index];
342             }
343         }
344
345         return value;
346     }
347
348     /**
349      * Sets the given value into the given array at the given index. This handles
350      * primitive arrays by assuming that the value given is a wrapper object and
351      * unwraps it.
352      *
353      * @param array The array to set into
354      * @param index The index to set the value at
355      * @param value The value to set (possibly wrapped primitive but could be
356      * an Object as well)
357      */

358     public static void setIntoArray(Object JavaDoc array, int index, Object JavaDoc value) {
359         Class JavaDoc type = array.getClass();
360         if (!type.isArray()) {
361             throw new IllegalArgumentException JavaDoc("Type not an array: " +
362                 type.getName());
363         }
364
365         Class JavaDoc compType = type.getComponentType();
366         if (compType == Boolean.TYPE) {
367             ((boolean[]) array)[index] = ((Boolean JavaDoc) value).booleanValue();
368         } else if (compType == Byte.TYPE) {
369             ((byte[]) array)[index] = ((Byte JavaDoc) value).byteValue();
370         } else if (compType == Character.TYPE) {
371             ((char[]) array)[index] = ((Character JavaDoc) value).charValue();
372         } else if (compType == Double.TYPE) {
373             ((double[]) array)[index] = ((Double JavaDoc) value).doubleValue();
374         } else if (compType == Float.TYPE) {
375             ((float[]) array)[index] = ((Float JavaDoc) value).floatValue();
376         } else if (compType == Integer.TYPE) {
377             ((int[]) array)[index] = ((Integer JavaDoc) value).intValue();
378         } else if (compType == Long.TYPE) {
379             ((long[]) array)[index] = ((Long JavaDoc) value).longValue();
380         } else if (compType == Short.TYPE) {
381             ((short[]) array)[index] = ((Short JavaDoc) value).shortValue();
382         } else {
383             ((Object JavaDoc[]) array)[index] = value;
384         }
385     }
386
387     /**
388      * Using the data structure (ie Collection, Map or arary instance) and key
389      * given, this sets the value given into the data structure. If the data
390      * structure is a Map, this uses the key as is. Otherwise this verifies that
391      * the key is an Integer and uses the intValue of that as the indices to set
392      * into the List, or array. If this is a Collection, an exception is thrown.
393      *
394      * @param dataStructure The data structure instance to retrieve the value
395      * from
396      * @param key The indices/key to use to retrieve the value
397      * @param value The value to set into the data structure
398      * @throws IllegalArgumentException If the type is Collection or if the key
399      * is the incorrect type or the data structure is not a valid data
400      * structure
401      */

402     public static void setValueIntoCollection(final Object JavaDoc dataStructure,
403             final Object JavaDoc key, final Object JavaDoc value) {
404
405         // Figure out what type the property is and handle it accordingly
406
if (dataStructure instanceof Map JavaDoc) {
407             ((Map JavaDoc) dataStructure).put(key, value);
408         } else {
409             Class JavaDoc type = dataStructure.getClass();
410             boolean isList = (List JavaDoc.class.isAssignableFrom(type));
411             boolean isCollection = (Collection JavaDoc.class.isAssignableFrom(type));
412             boolean isArray = (type.isArray());
413
414             if (!isList && !isArray && !isCollection) {
415                 throw new IllegalArgumentException JavaDoc("Invalid data structure type: " +
416                     type.getName());
417             }
418
419             int index = -1;
420             if (key instanceof Integer JavaDoc) {
421                 index = ((Integer JavaDoc) key).intValue();
422             } else {
423                 throw new IllegalArgumentException JavaDoc("Invalid indices/key: " + key +
424                     " for data strucutre of type " + type.getName());
425             }
426
427             if (List JavaDoc.class.isAssignableFrom(type)) {
428                 ((List JavaDoc) dataStructure).set(index, value);
429             } else if (Collection JavaDoc.class.isAssignableFrom(type)) {
430                 throw new IllegalArgumentException JavaDoc("You can not set a property " +
431                     "of type Collection using an indices. Use a List instead");
432             } else if (type.isArray()) {
433                 ObjectTools.setIntoArray(dataStructure, index, value);
434             }
435         }
436     }
437
438     /**
439      * Determines if the type given is a Collection or Map.
440      *
441      * @param type Class type to check
442      * @return True if the Class is assignable to Collection or Map
443      */

444     public static boolean isCollection(Class JavaDoc type) {
445         return (Map JavaDoc.class.isAssignableFrom(type) ||
446             Collection JavaDoc.class.isAssignableFrom(type));
447     }
448
449     /**
450      * Determines if the type of the given bean is a Collection or Map.
451      *
452      * @param object The Object whose Class to check
453      * @return True if the Class is assignable to Collection or Map
454      */

455     public static boolean isCollection(Object JavaDoc object) {
456         if (object == null) {
457             return false;
458         }
459
460         Class JavaDoc type = object.getClass();
461         return (Map JavaDoc.class.isAssignableFrom(type) ||
462             Collection JavaDoc.class.isAssignableFrom(type));
463     }
464
465     /**
466      * Determines if the type of the given bean is an array.
467      *
468      * @param object The Object whose Class to check
469      * @return True if the Class is assignable to an array
470      */

471     public static boolean isArray(Object JavaDoc object) {
472         if (object == null) {
473             return false;
474         }
475
476         Class JavaDoc type = object.getClass();
477         return type.isArray();
478     }
479
480     /**
481      * Determines if the type of the given bean is a Collection, Map or array,
482      * effectively a data structure of some kind.
483      *
484      * @param object The Object whose Class to check
485      * @return True if the Class is assignable to Collection or Map or an array
486      */

487     public static boolean isDataStructure(Object JavaDoc object) {
488         if (object == null) {
489             return false;
490         }
491
492         Class JavaDoc type = object.getClass();
493         return (type.isArray() || isCollection(type));
494     }
495
496     /**
497      * Creates an array instance that is the same as the type given. This means
498      * that the type given should be an array (ie Collection[][][]). This uses
499      * the List given to retrieve the dimensions of the array. The List given
500      * contains the indices that may be later used to set the array and therefore
501      * 1 is added to each value. If the type given is not as deep of an array as
502      * the List has indices, the array is created as deep as the indicies allow
503      * and the boolean flag inside the ArrayInfo struct called
504      * {@link ArrayInfo#complete complete} will be false. Likewise, if the List
505      * of indices is too large, the array is created and the complete flag is
506      * also false. The only case where the flag is true is when the depth of the
507      * array, the size of the indices list (minus start) are equal. i.e.<br/>
508      * <code>(depth of type) == (indices.size() - start)</code><br/>.
509      *
510      * @param type The type to create
511      * @param indices The list of indices to use
512      * @param start The place in the list to start
513      * @return A new ArrayInfo and never null. Failure is marked by the complete
514      * flag inside being false.
515      * @throws IllegalArgumentException If any of the indices in the List are
516      * not Integer objects
517      */

518     public static ArrayInfo createArray(final Class JavaDoc type, final List JavaDoc indices,
519             final int start) {
520         int size = indices.size();
521         int[] dims = new int[indices.size() - start];
522         ArrayInfo ai = new ArrayInfo();
523         ai.type = type;
524
525         int indexToUse = start;
526         int dimsIndex = 0;
527         Integer JavaDoc index;
528         while (ai.type.isArray() && indexToUse != size) {
529             try {
530                 index = (Integer JavaDoc) indices.get(indexToUse);
531             } catch (ClassCastException JavaDoc cce) {
532                 throw new IllegalArgumentException JavaDoc("Invalid index: " + cce);
533             }
534
535             dims[dimsIndex] = index.intValue() + 1;
536             ai.type = ai.type.getComponentType();
537             dimsIndex++;
538             indexToUse++;
539         }
540
541         // This sucks, but we need to check and possibly copy the dims array in
542
// case we created it too long
543
if (dimsIndex != dims.length) {
544             int[] oldDims = dims;
545             dims = new int[dimsIndex];
546             System.arraycopy(oldDims, 0, dims, 0, dims.length);
547         }
548
549         ai.complete = (indexToUse == size && !ai.type.isArray());
550         ai.array = Array.newInstance(ai.type, dims);
551         return ai;
552     }
553
554     /**
555      * A struct with information about arrays
556      */

557     public static class ArrayInfo {
558
559         /**
560          * The base type of the array. This should always return false for calls
561          * to isArray()
562          */

563         public Class JavaDoc type;
564
565         /**
566          * The array itself
567          */

568         public Object JavaDoc array;
569
570         /**
571          * Denotes that the array create was not a complete array
572          */

573         public boolean complete;
574     }
575 }
Popular Tags