|
Step #2: Handling Arrays
It's no big problem to detect an array. The method call f.getType() returns a Class object which "knows" all the attributes of the field. Therefore, if the field is an array:
Field f = fields[i];
Class type = f.getType();
Object value = f.get(obj);
if (type.isArray()) {
Class compType = type.getComponentType();
int length = Array.getLength(value);
for (int j = 0; j < length; j++) {
Object obj2 = Array.get(value, j);
System.out.println("Element " + j + " is of type " + compType +
" and has value=" + obj2);
}
}
When an array is located, the Array class is used to extract the data in the array.
Add Systematics to the Algorithm
In order not to end up with code that looks like patchwork, it's important to deal with objects systematically:
- Handle a null object.
- Handle an array.
- Handle each field in the object.
Furthermore, you're probably only interested in listing fields in classes from your own project. This means you should set up a filter for the packages you want to drill down into. This calls for an algorithm that goes something like this (pseudo-code):
handleObject(object):
if object is null then handleNull
else
if object is an array then
for each element in the array: handleObject(element)
else
if object is not from our project then call its toString method
else
for each field in the object: handleObject(field)
A first shot on a program, Reflection3, built according to these principles, can be found
here. To see how it works on arrays, Reflection3 contains these fields:
public int[] iArray = { 1, 2, 3 };
public String[] sArray = { "abc", "def" };
public int[][] i2Array = { { 1, 2, 3 }, { 7, 9 } };
public Integer[] integerArray = {new Integer(7), new Integer(13)};
public NumberFormat[] numberArray = { NumberFormat.getInstance(), null };
Reflection3 gives this output:
Class: keld.playground.examples.Reflection3
Field: iArray
Value=1 Value=2 Value=3
Field: sArray
Value=abc Value=def
Field: i2Array
Value=1 Value=2 Value=3
Value=7 Value=9
Field: integerArray
Value=7 Value=13
Field: numberArray
Value=java.text.DecimalFormat@674dc Value=NULL
All values are written out using their objects' toString() methods. As mentioned above, the primitive types are wrapped in classes, so it's always safe to use toString().
Collections and Maps
The examples above showed that Collections and Maps were listed nicely with these formats:
| Interface |
toString() format |
| Collection |
[element1, element2, ...] |
| Map |
{key1=value1, key2=value2, ...} |
This format is okay as long as the elements, keys, and values are simple types or objects that have a toString method which prints with a nice, readable format. For complex objects, it's necessary to do exactly the same kind of handling as you did above for array elements or fields in an object.
An improved version of toString() for a Collection looks like this:
private static void toStringForList(StringBuffer r, Collection list) {
r.append("[");
boolean first = true;
for (Iterator it = list.iterator(); it.hasNext();) {
if (!first) {
r.append(", ");
} else
first = false;
Object element = it.next();
handleObject(r, element);
}
r.append("]");
}
The highlighted statement shows how to recursively call handleObject for each element in the Collection. A StringBuffer has also been introduced to collect the formatted data. The final version of handleObject should return a String with the formatted data, so the user is free to use it as s/he likes.
The toString() for a Map follows the same style:
private static void toStringForMap(StringBuffer r, Map map) {
r.append("{");
boolean first = true;
Set keySet = map.keySet();
for (Iterator it = keySet.iterator(); it.hasNext();) {
if (!first) {
r.append(", ");
} else
first = false;
Object element = it.next();
handleObject(r, element);
r.append("=");
handleObject(r, map.get(element));
}
r.append("}");
}
The algorithm (in pseudocode) sketched above will have to be modified slightly:
handleObject(object):
if object is null then handleNull
else
if object is an array then
for each element in the array: handleObject(element)
else
if object is a Collection then handleCollection
else
if object is a Map then handleMap
else
if object is not from our project then call its toString method
else
for each field in the object: handleObject(field)
New on the Java Boutique:
New Review:
Time Management Made Easy with the Quartz Enterprise Job Scheduler
Why not just use the Java timer API? This open source scheduling
API boasts simplicity, ease-of-integration, a well-rounded feature
set, and it's free!
New Applet:
Reverse Complement
Reverse Complement is a simple applet that converts DNA or RNA
sequences into three useful formats.
Elsewhere on internet.com:
WebDeveloper Java
Lots of Java information on webdeveloper.com
WDVL Java
Thorough Java resource at the Web Developer's Virtual Library.
ScriptSearch Java
Hundreds of free Java code files to download.
jGuru: Your View of the Java Universe
Customizable portal with online training, FAQs, regular news updates, and tutorials.
|