Tutorials : Save Time with the Ultimate toString Method :

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)

How to Add Java Applets to Your Site

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.