View Javadoc

1   /*
2    * Copyright (c) 2003-2008 by Cosylab d. d.
3    *
4    * This file is part of Java-Common.
5    *
6    * Java-Common is free software: you can redistribute it and/or modify
7    * it under the terms of the GNU General Public License as published by
8    * the Free Software Foundation, either version 3 of the License, or
9    * (at your option) any later version.
10   *
11   * Java-Common is distributed in the hope that it will be useful,
12   * but WITHOUT ANY WARRANTY; without even the implied warranty of
13   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   * GNU General Public License for more details.
15   *
16   * You should have received a copy of the GNU General Public License
17   * along with Java-Common.  If not, see <http://www.gnu.org/licenses/>.
18   */
19  
20  package com.cosylab.introspection;
21  
22  import java.beans.FeatureDescriptor;
23  import java.lang.reflect.Constructor;
24  import java.lang.reflect.Field;
25  import java.lang.reflect.InvocationTargetException;
26  import java.lang.reflect.Member;
27  import java.lang.reflect.Method;
28  import java.lang.reflect.Modifier;
29  
30  /**
31   * This class helps create String representations of
32   * given objects using introspection. It also contains some
33   * methods that facilitate String manipulation.
34   * 
35   * @author  Miha Kadunc (miha.kadunc@cosylab.com)
36   * @version @@VERSION@@
37   */
38  public class DataFormatter {
39  
40  	/**
41  	 * Returns short name of the given Class object. Appends
42  	 * the appropriate number of "[]" sequences for arrays. 
43  	 * 
44  	 * @param aClass Class
45  	 * @return java.lang.String
46  	 */
47  	public static String toString(Class aClass) {
48  		if (aClass == null)
49  			return "null";
50  		StringBuffer t = new StringBuffer();
51  		if (aClass.isArray()) {
52  			t.append(toString(aClass.getComponentType()));
53  			int dim = aClass.getName().lastIndexOf("[") - aClass.getName().indexOf("[") + 1;
54  			for (int i = 0; i < dim; i++)
55  				t.append("[ ]");
56  		} else {
57  			t.append(aClass.getName());
58  			int i = aClass.getName().lastIndexOf(".") + 1;
59  			if (i > 0)
60  				t.delete(0, i);
61  		}
62  		return t.toString();
63  	}
64  
65  	/**
66  	 * Returns a String representing an array of Class objects,
67  	 * separated by ","
68  	 * 
69  	 * @param array Class[]
70  	 * @return parameter names
71  	*/
72  	public static String toString(Class[] array) {
73  		StringBuffer result = new StringBuffer(" ");
74  		for (int i = 0; i < array.length; i++) {
75  			if (i > 0)
76  				result.append(", ");
77  			result.append(toString(array[i]));
78  		}
79  		result.append(" ");
80  		return result.toString();
81  	}
82  
83  	/**
84  	 * Returns a String representation of a constructor.
85  	 * 
86  	 * @param aConstructor Constructor
87  	 * @param showParameters boolean
88  	 * @return java.lang.String
89  	*/
90  	public static String toString(Constructor aConstructor, boolean showParameters) {
91  		String ret = aConstructor.getName();
92  		if (showParameters)
93  			ret = ret + " (" + toString(aConstructor.getParameterTypes()) + ")";
94  		return ret;
95  	}
96  
97  	/**
98  	 * Returns a String representation of the given field, 
99  	 * showing its type and its name.
100 	 * 
101 	 * @param aField Field
102 	 * @return java.lang.String
103 	 */
104 	public static String toString(Field aField) {
105 		return toString(aField, true);
106 	}
107 
108 	/**
109 	 * Returns a String representation of the given field,
110 	 * showing its type iff the showType parameter is set
111 	 * to true.
112 	 * 
113 	 * @param aField Field
114 	 * @param showType boolean
115 	 * @return java.lang.String
116 	 */
117 	public static String toString(Field aField, boolean showType) {
118 		String ret = "";
119 		if (showType)
120 			ret = ret + toString(aField.getType()) + " ";
121 		ret = ret + aField.getName();
122 		return ret;
123 	}
124 
125 	/**
126 	 * Returns a String representation of the specified member,
127 	 * and its return and parameter types.
128 	 * 
129 	 * @param aMember Member
130 	 * @return java.lang.String
131 	 */
132 	public static String toString(Member aMember) {
133 		return toString(aMember, true, true);
134 	}
135 
136 	/**
137 	 * Returns a String representation of the specified member,
138 	 * and its return and parameter types only if specified so by
139 	 * the showType and showParameters flags.
140 	 * 
141 	 * @param aMember Member
142 	 * @param showType boolean
143 	 * @param showParameters boolean
144 	 * @return java.lang.String
145 	*/
146 	public static String toString(Member aMember, boolean showType, boolean showParameters) {
147 		if (aMember == null)
148 			return "null";
149 		if (aMember.getClass().equals(Field.class))
150 			return toString((Field)aMember, showType);
151 		if (aMember.getClass().equals(Method.class))
152 			return toString((Method)aMember, showType, showParameters);
153 		if (aMember.getClass().equals(Constructor.class))
154 			return toString((Constructor)aMember, showParameters);
155 		else
156 			return "";
157 	}
158 
159 	/**
160 	 * Returns a String representation of the given method, 
161 	 * showing also its type and parameter types.
162 	 * 
163 	 * @param aMethod Method
164 	 * @return java.lang.String
165 	 */
166 	public static String toString(Method aMethod) {
167 		return toString(aMethod, true, true);
168 	}
169 
170 	/**
171 	 * Returns a String representation of the given method, 
172 	 * showing also its type and parameter types iff specified.
173 	 * 
174 	 * @param aMethod Method
175 	 * @param showType boolean
176 	 * @param showParameters boolean
177 	 * @return java.lang.String
178 	 */
179 	public static String toString(Method aMethod, boolean showType, boolean showParameters) {
180 		String ret = "";
181 		if (showType)
182 			ret = ret + toString(aMethod.getReturnType()) + " ";
183 		ret = ret + aMethod.getName();
184 		if (showParameters)
185 			ret = ret + " (" + toString(aMethod.getParameterTypes()) + ") ";
186 		return ret;
187 	}
188 
189 	/**
190 	 * Returns an array of String representations of Class objects
191 	 * contained in the given array.
192 	 * 
193 	 * @param array Class[]
194 	 * @return parameter names
195 	 */
196 	public static String[] toStringArray(Class[] array) {
197 		String[] result = new String[array.length];
198 		for (int i = 0; i < array.length; i++) {
199 			result[i] = (toString(array[i]));
200 		}
201 		return result;
202 	}
203 
204 	/**
205 	 * Returns an array of String representations of 
206 	 * members in the given array. Parameters can be set to
207 	 * show return or parameter types.
208 	 * 
209 	 * @param array Member[]
210 	 * @param showType boolean
211 	 * @param showParameters boolean
212 	 * @return String[] array of string representations of the members
213 	 */
214 	public static String[] toStringArray(Member[] array, boolean showType, boolean showParameters) {
215 		String[] result = new String[array.length];
216 		for (int i = 0; i < array.length; i++) {
217 			result[i] = (toString(array[i], showType, showParameters));
218 		}
219 		return result;
220 	}
221 
222 	/**
223 	 * Returns an array of String representations of 
224 	 * feature descriptors in the given array.
225 	 * 
226 	 * @param array FeatureDescriptor[]
227 	 * @param showType boolean
228 	 * @param showParameters boolean
229 	 * @return String[] array of string representations of the members
230 	 */
231 	public static String[] toStringArray(
232 		FeatureDescriptor[] array,
233 		boolean showType,
234 		boolean showParameters) {
235 
236 		return toStringArray(array);
237 	}
238 
239 	/**
240 	 * Returns an array of String representations of 
241 	 * objects in the given array.
242 	 * 
243 	 * @param array Object[]
244 	 * @return String[]
245 	 */
246 	public static String[] toStringArray(Object[] array) {
247 		if (array == null)
248 			return new String[0];
249 		String[] result = new String[array.length];
250 		for (int i = 0; i < array.length; i++) {
251 			result[i] = array[i].toString();
252 		}
253 		return result;
254 	}
255 
256 	/**
257 	 * Returns a default String representation of an array.
258 	 * 
259 	 * @param array java.lang.Object
260 	 * @return java.lang.String
261 	 */
262 	public static String arrayToString(Object array) {
263 		return arrayToString(array, "");
264 	}
265 	/**
266 	 * Returns a String representation of an array with
267 	 * the specified text in the beginning of each line.
268 	 * 
269 	 * @param array java.lang.Object
270 	 * @param lineStart java.lang.String
271 	 * @return java.lang.String
272 	 */
273 	public static String arrayToString(Object array, String lineStart) {
274 		if (array.getClass().isArray()) {
275 			Object[] fixedArray;
276 			StringBuffer result = new StringBuffer();
277 
278 			result.append(lineStart);
279 			result.append("Array of class: ");
280 			result.append(array.getClass().getComponentType().getName());
281 			if (array.getClass().getComponentType().isPrimitive())
282 				fixedArray = convertPrimitiveArray(array);
283 			else
284 				fixedArray = (Object[])array;
285 			result.append(" length: ");
286 			result.append(fixedArray.length);
287 			result.append("\n");
288 
289 			for (int i = 0; i < fixedArray.length; i++) {
290 				result.append(lineStart);
291 				result.append(" [");
292 				result.append(i);
293 				result.append("] ");
294 				result.append(fixedArray[i].toString());
295 				result.append("\n");
296 			}
297 			return result.toString();
298 		} else
299 			throw new IllegalArgumentException("array parameter is not an array");
300 	}
301 	/**
302 	 * Converts an array of primitive values into Java
303 	 * wrappers.
304 	 * @param value Object
305 	 * @return Object[]
306 	 */
307 	public static Object[] convertPrimitiveArray(Object value) {
308 		if (!(value.getClass().isArray() && value.getClass().getComponentType().isPrimitive()))
309 			throw new IllegalArgumentException("value is not a primitive Array");
310 		try {
311 			Class type = value.getClass().getComponentType();
312 			Object[] retVal = null;
313 			if (type.toString().equals("int")) {
314 				int[] tempVal = (int[])value;
315 				retVal = new Integer[tempVal.length];
316 				for (int i = 0; i < tempVal.length; i++)
317 					retVal[i] = new Integer(tempVal[i]);
318 			}
319 			if (type.toString().equals("double")) {
320 				double[] tempVal = (double[])value;
321 				retVal = new Double[tempVal.length];
322 				for (int i = 0; i < tempVal.length; i++)
323 					retVal[i] = new Double(tempVal[i]);
324 			}
325 			if (type.toString().equals("long")) {
326 				long[] tempVal = (long[])value;
327 				retVal = new Long[tempVal.length];
328 				for (int i = 0; i < tempVal.length; i++)
329 					retVal[i] = new Long(tempVal[i]);
330 			}
331 			if (type.toString().equals("short")) {
332 				short[] tempVal = (short[])value;
333 				retVal = new Short[tempVal.length];
334 				for (int i = 0; i < tempVal.length; i++)
335 					retVal[i] = new Short(tempVal[i]);
336 			}
337 			if (type.toString().equals("byte")) {
338 				byte[] tempVal = (byte[])value;
339 				retVal = new Byte[tempVal.length];
340 				for (int i = 0; i < tempVal.length; i++)
341 					retVal[i] = new Byte(tempVal[i]);
342 			}
343 			if (type.toString().equals("char")) {
344 				char[] tempVal = (char[])value;
345 				retVal = new Character[tempVal.length];
346 				for (int i = 0; i < tempVal.length; i++)
347 					retVal[i] = new Character(tempVal[i]);
348 			}
349 			if (type.toString().equals("float")) {
350 				float[] tempVal = (float[])value;
351 				retVal = new Float[tempVal.length];
352 				for (int i = 0; i < tempVal.length; i++)
353 					retVal[i] = new Float(tempVal[i]);
354 			}
355 			return retVal;
356 		} catch (Exception e) {
357 			throw new IllegalArgumentException("value could not be converted");
358 		}
359 	}
360 	/**
361 	 * Returns number of lines (separated by \n)
362 	 * contained in the given String.
363 	 * 
364 	 * @param lines java.lang.String
365 	 * @return int
366 	 */
367 	public static int getLineCount(String lines) {
368 		int count = 0;
369 		int pos = -1;
370 		int maxPos = lines.length();
371 
372 		do {
373 			pos = lines.indexOf(10, pos + 1);
374 			count++;
375 		} while ((pos > -1) && (pos < maxPos));
376 
377 		return count;
378 	}
379 
380 	/**
381 	 * Splits a given string into multiple strings, each containing
382 	 * a single line (separated by \n)
383 	 * 
384 	 * @param stringToSplit String
385 	 * @return int
386 	 */
387 	public static String[] splitStringByLines(String stringToSplit) {
388 		int end = -1;
389 		int start = 0;
390 		int maxPos = stringToSplit.length();
391 		java.util.ArrayList list = new java.util.ArrayList();
392 		do {
393 			end = stringToSplit.indexOf(10, start);
394 			if ((end >= 0) && (end < maxPos) && (start >= 0) && (start < maxPos))
395 				list.add(stringToSplit.substring(start, end));
396 			start = end + 1;
397 		} while ((end > -1) && (end < maxPos));
398 		String[] retVal = new String[list.size()];
399 		list.toArray(retVal);
400 		return retVal;
401 	}
402 
403 	public static String[] splitStringOnCapitals(String stringToSplit) {
404 		String[] rez = stringToSplit.split("[A-Z]");
405 		int prev = 0;
406 		for (int i = 1; i < rez.length; i++) {
407 			prev = prev + rez[i - 1].length();
408 			rez[i] = stringToSplit.charAt(prev) + rez[i];
409 		}
410 		return rez;
411 	}
412 	/**
413 	 * Creates a default String representation of an array.
414 	 * 
415 	 * @param array java.lang.Object
416 	 * @return java.lang.String
417 	 */
418 	public static String unpackArray(Object array) {
419 		return unpackArray(array, "", 0);
420 	}
421 	/**
422 	 * Creates a String representation of an array, putting
423 	 * the passed lineStart at the beginning of each line.
424 	 *
425 	 * @param array java.lang.Object
426 	 * @param lineStart java.lang.String
427 	 * @return java.lang.String
428 	 */
429 	public static String unpackArray(Object array, String lineStart) {
430 		return unpackArray(array, lineStart, 0);
431 	}
432 	/**
433 	 * Creates a String representation of an array, putting
434 	 * the passed lineStart at the beginning of each line. Level
435 	 * specifies the recursion depth.
436 	 *
437 	 * @param array java.lang.Object
438 	 * @param lineStart java.lang.String
439 	 * @param level int
440 	 * @return java.lang.String
441 	 */
442 	public static String unpackArray(Object array, String lineStart, int level) {
443 		StringBuffer result = new StringBuffer();
444 		Class type = array.getClass().getComponentType();
445 		result.append("[Array of " + type + "], length = " + java.lang.reflect.Array.getLength(array));
446 		Object[] list = null;
447 		if (type.isPrimitive()) {
448 			list = convertPrimitiveArray(array);
449 		} else
450 			list = (Object[])array;
451 		for (int i = 0; i < list.length; i++)
452 			result.append(
453 				"\n"
454 					+ lineStart
455 					+ "   |("
456 					+ i
457 					+ ") "
458 					+ unpackReturnValue(list[i], lineStart + "  ", level - 1,true));
459 		return result.toString();
460 	}
461 	/**
462 	 * Uses introspection to unpack any type of return value operations might
463 	 * return. It does that recursively to the level of max_recursion_level. 
464 	 * It omitts methods, such as hashCode, clone etc.
465 	 *
466 	 * @param value Object
467 	 * @param start String
468 	 * @param level int
469 	 * @return String
470 	 */
471 	public static String unpackReturnValue(Object value, String start, int level) {
472 		return unpackReturnValue(value, start, level, false);
473 	}
474 	/**
475 	 * Uses introspection to unpack any type of return value operations might
476 	 * return. If expand is true, it does that recursively to the level of max_recursion_level. 
477 	 * It omitts methods, such as hashCode.
478 	 *
479 	 * @param value Object
480 	 * @param start String
481 	 * @param level int
482 	 * @param expand boolean
483 	 * @return String
484 	 */
485 	public static String unpackReturnValue(Object value, String start, int level, boolean expand) {
486 		StringBuffer result = new StringBuffer(500);
487 		if (value != null) {
488 			Class type = value.getClass();
489 			if (type.isArray()) {
490 				result.append(unpackArray(value, start, level));
491 			} else {
492 				if (value instanceof java.lang.String || 
493 						ClassIntrospector.isPrimitiveWrapper(value.getClass()) ||
494 						value instanceof java.lang.Class
495 						) {
496 					result.append(value.toString());
497 				} else {
498 					if (level < 0)
499 						return (value.getClass() + " (Recursion level exceeded)");
500 					else {
501 						result.append(value.toString());
502 						if (expand) {
503 							result.append('\n');
504 							result.append(start);
505 							result.append("  (" + type.getName() + ")");
506 							java.lang.reflect.Field[] fields = type.getFields();
507 
508 							for (int j = 0; j < fields.length; j++) {
509 								if (!Modifier.isStatic(fields[j].getModifiers())
510 									&& Modifier.isPublic(fields[j].getModifiers())) {
511 
512 									Field curField = fields[j];
513 									curField.setAccessible(true);
514 
515 									result.append('\n');
516 									result.append(start);
517 									result.append("  |- ");
518 									result.append(curField.getName());
519 									result.append(": ");
520 
521 									try {
522 										result.append(
523 											unpackReturnValue(curField.get(value), start + "  | ", level - 1,expand));
524 									} catch (IllegalArgumentException e) {
525 										result.append("Exception: ");
526 										result.append(e.toString());
527 									} catch (IllegalAccessException e) {
528 										result.append("Exception: ");
529 										result.append(e.toString());
530 									}
531 								}
532 							}
533 
534 							java.lang.reflect.Method[] methods = type.getMethods();
535 							for (int j = 0; j < methods.length; j++) {
536 								if (java.lang.reflect.Modifier.isPublic(methods[j].getModifiers())) {
537 									java.lang.reflect.Method curMet = methods[j];
538 									if ((curMet.getParameterTypes().length == 0)
539 										&& (curMet.getReturnType().isPrimitive() || level > 0)
540 										&& (!curMet.getReturnType().equals(Void.TYPE))
541 										&& (curMet.getName().startsWith("is") || curMet.getName().startsWith("get"))
542 										&& (!curMet.getName().equals("getClass"))) {
543 
544 										curMet.setAccessible(true);
545 										
546 										result.append("\n");
547 										result.append(start);
548 										result.append("  |- ");
549 										result.append(curMet.getName());
550 										result.append(" : ");
551 										try {
552 											result.append(
553 												unpackReturnValue(curMet.invoke(value, null), start + "  | ", level - 1,expand));
554 										} catch (IllegalArgumentException e) {
555 											result.append("Exception: ");
556 											result.append(e.toString());
557 										} catch (IllegalAccessException e) {
558 											result.append("Exception: ");
559 											result.append(e.toString());
560 										} catch (InvocationTargetException e) {
561 											result.append("Exception: ");
562 											result.append(e.getCause().toString());
563 										}
564 									}
565 								}
566 							}
567 						}
568 					}
569 				}
570 			}
571 			return result.toString();
572 		} else
573 			return ("null");
574 	}
575 	/**
576 	 * Unpacks the given values and creates their String representations.
577 	 * 
578 	 * 
579 	 * @param names java.lang.String[]
580 	 * @param values java.lang.Object[]
581 	 * @return java.lang.String
582 	 */
583 	public static String unpackValues(String[] names, Object[] values) {
584 		return unpackValues(names, values, ":");
585 	}
586 	/**
587 	 * Unpacks the given values and creates their String representations.
588 	 * The names and values are separated by the specified delimiter
589 	 * 
590 	 * @param names java.lang.String[]
591 	 * @param values java.lang.Object[]
592 	 * @param delimiter String
593 	 * @return java.lang.String
594 	 */
595 	public static String unpackValues(String[] names, Object[] values, String delimiter) {
596 		return unpackValues(names, values, delimiter, false);
597 	}
598 	/**
599 	 * Unpacks the given values and creates their String representations.
600 	 * The names and values are separated by the specified delimiter and the
601 	 * values are expanded and analyzed recursively, if specified.
602 	 * 
603 	 * @param names java.lang.String[]
604 	 * @param values java.lang.Object[]
605 	 * @param delimiter String
606 	 * @param expand boolean
607 	 * @return java.lang.String
608 	 */
609 	public static String unpackValues(
610 		String[] names,
611 		Object[] values,
612 		String delimiter,
613 		boolean expand) {
614 		StringBuffer result = new StringBuffer();
615 		for (int i = 0; i < values.length; i++) {
616 			result.append("    ");
617 			result.append(names[i]);
618 			result.append(delimiter);
619 			result.append(" ");
620 			result.append(unpackReturnValue(values[i], "      ", 0, expand));
621 			result.append("\n");
622 		}
623 		return result.toString();
624 	}
625 }