KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > inversoft > util > typeconverter > BaseTypeConverter


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.typeconverter;
8
9
10 import java.lang.reflect.Array JavaDoc;
11 import java.util.StringTokenizer JavaDoc;
12
13 import com.inversoft.util.ReflectionTools;
14 import com.inversoft.util.StringTools;
15
16
17 /**
18  * This class is the base type converter for all the type
19  * converters it is also the type converter that handles
20  * strings and arrays of strings. This converter contains
21  * implementation for all the type converter methods and
22  * also includes standard implementations for the convert,
23  * convertArray, convertArrayToArray, convertToArray and
24  * convertStringToArray. In most cases, these methods do
25  * not need to be overridden. See each method for details
26  * on what exactly the method does in order to help
27  * determine if overriding is necessary.
28  *
29  * @author Brian Pontarelli
30  */

31 public class BaseTypeConverter implements TypeConverter {
32
33     /**
34      * <p>
35      * If the convertTo class is an array, this method calls convertToArray passing
36      * it the value and the convertTo component type (by calling the getComponentType
37      * method of java.lang.Class).
38      * </p>
39      *
40      * <p>
41      * If the value is an instanceof an array, this method calls the convertArray
42      * method passing it the value, cast to an array and the convertTo type.<p>
43      * Otherwise, this method calls convertString passing it the value toString and
44      * the convertTo type.
45      * </p>
46      *
47      * <p>
48      * If the value is null, then convertString is called to handle primitive
49      * values and any converts that wish to handle null values differently. If
50      * the value is an instance of the convertTo type, this returns the value.
51      * </p>
52      *
53      * <p>
54      * Sub-classes should only override this method if they intend to handle conversion
55      * between two Object types, both of which are NOT String. For example, if a
56      * sub-class wished to convert Integer objects to Long objects, it could do that
57      * in this method. It is a good idea however, that sub-classes call this
58      * implementation if they do not handle the conversion.
59      * </p>
60      *
61      * @param value The value to convert
62      * @param convertTo The type to convert the value to
63      * @return The converted value or null if the value is null. This returns value
64      * if value is an instance of the convertTo type
65      * @throws TypeConversionException If there was a problem converting the given
66      * value to the given type
67      */

68     public Object JavaDoc convert(Object JavaDoc value, Class JavaDoc convertTo) throws TypeConversionException {
69
70         // If the value is null, no use in converting it
71
if (value == null) {
72             return convertString((String JavaDoc) value, convertTo);
73         }
74
75         // Handles the case where the value is the same type or sub-type as the convertTo
76
if (convertTo.isInstance(value)) {
77             return value;
78         }
79
80         if (convertTo.isArray()) {
81             return convertToArray(value, convertTo.getComponentType());
82         }
83
84         // This handles the case where the value is an array of an assignable type
85
// with length one
86
if (value instanceof Object JavaDoc []) {
87             return convertArray( (Object JavaDoc []) value, convertTo);
88         }
89
90         return convertString(value.toString(), convertTo);
91     }
92
93     /**
94      * <p>
95      * This method is usually the only method that needs to be overridden in sub-classes
96      * This is where a String value is converted to the correct type. Normally, it is a
97      * good idea to check if the convertTo type is an array and call convertStringToArray
98      * passing it the value, null for the delimiter and the component type of the convertTo
99      * parameter.
100      * </p>
101      *
102      * <p>
103      * This implementation does the above check passing null for the delimiter parameter
104      * (see convertStringToArray for an explaination of this parameter) if the check
105      * succeeds. Otherwise, this method returns the value parameter since the value
106      * parameter is already a String. If the value is null, empty or whitespace then this
107      * returns null.
108      * </p>
109      *
110      * <p>
111      * This is an important distinction because normally empty Strings or whitspace Strings
112      * are considered non-null, but this method treats them as nulls.
113      * </p>
114      *
115      * @param value The String value to convert to the given type
116      * @param convertTo The type to convert to
117      * @return Either the value parameter itself or an array version of the String value, if
118      * the convertTo type is an array. If the value is null, empty, or whitespace
119      * then this returns null
120      * @throws TypeConversionException If the convertTo type is an array and
121      * the convertStringToArray method throws an exception
122      */

123     public Object JavaDoc convertString(String JavaDoc value, Class JavaDoc convertTo) throws TypeConversionException {
124
125         // If the value is null, no use in converting it
126
if (StringTools.isTrimmedEmpty(value)) {
127             return null;
128         }
129
130         if (convertTo.isArray()) {
131             return convertStringToArray(value, null, convertTo.getComponentType());
132         }
133
134         return value;
135     }
136
137     /**
138      * <p>
139      * If the convertTo type parameter is an array, this method calls the convertArrayToArray
140      * method with the parameters passed to this method. If the values is an array of
141      * length 1, it first checks if the array value at indices 0 is an instanceof the
142      * convertTo type, it returns the value at indices 0. If not, it returns the result
143      * of calling convert with the value at indices 0 and the convertTo type.
144      * </p>
145      *
146      * <p>
147      * Otherwise, this method throws an exception because it is normally not needed to
148      * convert an array to an object. If the values array is null, then this method
149      * returns null.
150      * </p>
151      *
152      * @param values The array of values to convert to the given type
153      * @param convertTo The type to convert to
154      * @return Either the result of calling the convertArrayToArray method if the
155      * convertTo type is an array, or the convert method if the values
156      * array is of length 1. If the values is null, then this returns null.
157      * If values length is zero, this returns null. If values is length 1
158      * but the element at indices 0 is null, this returns null.
159      * @throws TypeConversionException If either the convertArray or convert
160      * method throw an exception (depending on which method is called)
161      * or always (see method comment)
162      */

163     public Object JavaDoc convertArray(Object JavaDoc[] values, Class JavaDoc convertTo)
164     throws TypeConversionException {
165
166         // If the values is null, no use in converting it
167
if (values == null) {
168             return null;
169         }
170
171         if (convertTo.isArray()) {
172             return convertArrayToArray(values, convertTo);
173         }
174
175         // If the array is length zero
176
if (values.length == 0) {
177             return null;
178         }
179
180         if (values.length == 1) {
181             if (convertTo.isInstance(values[0])) {
182                 return values[0];
183             }
184
185             return convert(values[0], convertTo);
186         }
187
188         throw new TypeConversionException("BaseTypeConverter does not handle" +
189             " converting an array with size not equal to one to an object");
190     }
191
192     /**
193      * If the convertTo type is an array, this method uses the component type for the
194      * convertTo type. Using the convertTo, a new array is constructed of that type with
195      * the same length as the values array. Then, each object in the values array is
196      * checked to see if it is an instanceof the convertTo type. If it is, the array
197      * position is set to the value at the same position. If it is not, the the value
198      * is converted to the convertTo type and stored in the new array. This is done by
199      * calling the convert method with each position in the values array. Finally, the
200      * fully converted array is returned. If the values array is null or length 0, then
201      * this returns null.
202      *
203      * @param values The array to convert to an array of the given type
204      * @param convertTo The type to convert to an array of. if this parameter is an array
205      * type, then this method converts to that type.
206      * the an array of the type is converted to.
207      * @return The converted array or null if the values array is null or length 0.
208      * @throws TypeConversionException If the convert method throws a TypeConversionException
209      * when each of the positions in the values array are converted
210      */

211     public Object JavaDoc [] convertArrayToArray(Object JavaDoc [] values, Class JavaDoc convertTo)
212             throws TypeConversionException {
213
214         // If the value is null, no use in converting it
215
if (values == null || values.length == 0) {
216             return null;
217         }
218
219         if (convertTo.isArray()) {
220             convertTo = convertTo.getComponentType();
221         }
222
223         Object JavaDoc [] array;
224         if (convertTo.isPrimitive()) {
225             Class JavaDoc wrapper = ReflectionTools.convertToWrapper(convertTo);
226             array = (Object JavaDoc []) Array.newInstance(wrapper, values.length);
227         } else {
228             array = (Object JavaDoc []) Array.newInstance(convertTo, values.length);
229         }
230
231         for (int i = 0; i < array.length; i++) {
232             if (values[i] != null &&
233                     convertTo.isAssignableFrom(values[i].getClass())) {
234                 array[i] = values[i];
235             } else {
236                 array[i] = convert(values[i], convertTo);
237             }
238         }
239
240         return array;
241     }
242
243     /**
244      * If the value is an instanceof an array, then this method calls the
245      * convertArrayToArray method by casting the value to an Object array and passing
246      * the convertTo type. Otherwise, convertStringToArray is called with the value
247      * converted to a String using the toString method, the convertTo type and null for
248      * the delimiter (see convertStringToArray for an explaination of this parameter).
249      * If the value is null, then this returns null.
250      *
251      * @param value The value to convert to an array of the given type or simply the
252      * given type if the given type is an array
253      * @param convertTo The type to convert to an array of. If this parameter is an
254      * array type, this method converts to that type.
255      * @return The value converted to an array or null if the value is null
256      * @throws TypeConversionException If convertArrayToArray or
257      * convertStringToArray throw a TypeConversionException (depending
258      * on which one is called)
259      */

260     public Object JavaDoc [] convertToArray(Object JavaDoc value, Class JavaDoc convertTo) throws TypeConversionException {
261
262         // If the value is null, no use in converting it
263
if (value == null) {
264             return null;
265         }
266
267         if (value instanceof Object JavaDoc []) {
268             return convertArrayToArray((Object JavaDoc []) value, convertTo);
269         }
270
271         return convertStringToArray(value.toString(), null, convertTo);
272     }
273
274     /**
275      * If the delimiter parameter is not empty or null it is used. Otherwise a
276      * standard set of delimiters are used (comma, semi-colon, tab, and new line).<p>
277      * Using this delimiter, the string is tokenized and each token is passed to
278      * the convertString method, along with the convertTo type. The result is added
279      * to a new array of the given convertTo type or the convertTo type (if the
280      * convertTo type is an array type). This means that the order of the tokens
281      * determines the order of the array elements and the array is as long as
282      * the number of tokens. If the value is null, then this returns null
283      *
284      * @param value The string to convert to an array
285      * @param delimiter The string to use as the delimiter when tokenizing
286      * @param convertTo The type to convert the string to. Can either be an array
287      * or an object
288      * @return The array generated by the conversion or null if the value is null
289      * @throws TypeConversionException If the call to convertString throws an
290      * exception
291      */

292     public Object JavaDoc[] convertStringToArray(String JavaDoc value, String JavaDoc delimiter,
293             Class JavaDoc convertTo) throws TypeConversionException {
294
295         // If the value is null, no use in converting it
296
if (value == null) {
297             return null;
298         }
299
300         if (convertTo.isArray()) {
301             convertTo = convertTo.getComponentType();
302         }
303
304         // StringTokenizer clobbers a String that starts with a delimiter, and
305
// we want to capture that condition. Therefore, we check that here so
306
// that the array length and array values are correct
307
boolean startsWithDelim = false;
308         StringTokenizer JavaDoc st;
309         if (StringTools.isEmpty(delimiter)) {
310             st = new StringTokenizer JavaDoc(value, ",;\t\n");
311             startsWithDelim = (value.length() > 0) ?
312                 (",;\t\n".indexOf(value.charAt(0)) != -1) : false;
313         } else {
314             st = new StringTokenizer JavaDoc(value, delimiter);
315             startsWithDelim = (value.length() > 0) ?
316                 (delimiter.indexOf(value.charAt(0)) != -1) : false;
317         }
318
319         // Increment the count if the string starts with a delimiter
320
int count = st.countTokens();
321         if (startsWithDelim) {
322             count++;
323         }
324
325         // Use the wrapper for primitives
326
Object JavaDoc [] array;
327         if (convertTo.isPrimitive()) {
328             Class JavaDoc wrapper = ReflectionTools.convertToWrapper(convertTo);
329             array = (Object JavaDoc []) Array.newInstance(wrapper, count);
330         } else {
331             array = (Object JavaDoc []) Array.newInstance(convertTo, count);
332         }
333
334         // Handle the starts with a delimiter case by setting the first position
335
// to the conversion of an empty string
336
int i = 0;
337         if (startsWithDelim) {
338             array[0] = convertString("", convertTo);
339             i++;
340         }
341
342         for (; i < array.length; i++) {
343             array[i] = convertString(st.nextToken(), convertTo);
344         }
345
346         return array;
347     }
348 }
Popular Tags