Apache Commons ToStringBuilder

I have found the humble Java toString() to be one of the most useful and powerful techniques in debugging and troubleshooting Java applications. That is only true, unfortunately, when and if the developers on the team override the Object.toString() method to provide useful details.

The usefulness of the Java toString() method is documented in Joshua Bloch's Effective Java (Item 10 in the Second Edition and Item 9 in the First Edition). The toString() method's usefulness is so proven that some languages newer than Java have taken the concept even further. Scala, for example, provides a type of class (case class) in which a reasonable default toString() is provided. ActionScript provides an ObjectUtil.toString() method that can be used to print an object's contents even when that object's class does not have its own toString implementation.

Unfortunately, toString can be an oft-forgotten method in a new class's implementation and, even when implemented, may suffer some implementation details that reduce its usefulness. These negative considerations include lack of maintenance of the toString() method (such as not adding important new data members of a class to it), lack of standard format or coverage of different data types (especially Collections), handling of nulls, and the sheer tedium associated with hand-writing toString() methods.

The vast Apache Commons project (formerly known as Jakarta Commons) is rich with useful libraries, but I think many of them are often unappreciated by many of us because we're unaware of them. While there have been several blog entries and articles on Apache Commons, I still find myself learning about some of the useful features available in the Apache Commons project (which is really a repository of multiple libraries that in many ways are not very related). Perhaps even more surprisingly, I find that even some relatively experienced Java developers who are familiar with some of the more common pieces of Apache Commons (such as Commons Logging) are not familiar with the ToStringBuilder in the Commons Lang component.

The beauty of the Commons ToStringBuilder is that it helps overcome many of the issues that have traditionally reduced the effectiveness of toString() method implementations. In the remainder of this blog entry, I intend to demonstrate how easy it is to apply ToStringBuilder to any Java class. I will do this using several simple classes that mostly consist of data members and toString() implementations using ToStringBuilder.

The first class with code listed here (ToStringDemonstrator) is the main class for running the examples that demonstrate ToStringBuilder in action. This class doesn't do much itself, but it does print out the contents of each object via the objects' toString() implementations.

ToStringDemonstrator.java

package dustin.examples.common;

/**
 * This example class demonstrates the high utility of the Apache Commons
 * ToStringBuilder class and is associated with a blog entry at
 * http://marxsoftware.blogspot.com/.
 * 
 * @author Dustin
 */
public class ToStringDemonstrator
{
   /**
    * Main executable for demonstrating Jakarta Commons ToStringBuilder.
    * 
    * @param args The command line arguments; none expected.
    */
   public static void main(String[] arguments)
   {
      final Parent parent = new Parent();
      System.out.println("PARENT:\n" + parent + "\n");

      final ReflectionChild reflectionChild = new ReflectionChild();
      System.out.println("CHILD/REFLECTION:\n" + reflectionChild + "\n");

      final ReflectionChildExcludes reflectionExcludesChild =
         new ReflectionChildExcludes();
      System.out.println(
         "CHILD/REFLECTION/EXCLUDES:\n" + reflectionExcludesChild + "\n");

      final TransientsChild transientsChild = new TransientsChild();
      System.out.println("CHILD/TRANSIENTS:\n" + transientsChild + "\n");

      final ExplicitChild explicitChild = new ExplicitChild();
      System.out.println("CHILD/EXPLICIT:\n" + explicitChild + "\n");

      final StyleChild styleChild = new StyleChild();
      System.out.println("CHILD/STYLE:\n" + styleChild + "\n");
   }
}

The main executable class whose code is shown above instantiates several objects and implicitly calls their toString() implementations via System.out calls on those instantiated objects. The objects include one parent class and a bunch of its child classes. The inheritance hierarchy helps demonstrate ToStringBuilder's treatment of parent data members in child toString() implementations.

The output of each class's toString() implementation demonstrates a different characteristic of ToStringBuilder. I will go through the code for each object along with the String representation of each class generated by ToStringBuilder.

Parent.java

This class serves as a parent class for the rest of the classes in the example. It also demonstrates ToStringBuilder.reflectionToString(Object). This method allows one to take advantage of reflection and, in a single line of code, return the String representation of the class's data members. In this example, the object's this reference is passed to the method so that the same object's String representation is generated via reflection. Note, however, that this could be used on a separate class instance as well if that instance was significant to this class but did not have its own useful toString() implementation.

This class intentionally includes many different attributes of different types and with different modifiers (such as static and transient) to more fully demonstrate default behavior and custom behavior of the ToStringBuilder and related classes.

package dustin.examples.common;

import java.util.ArrayList;
import java.util.EnumMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang.builder.ToStringBuilder;

/**
 * An example class to which Apache Commons ToStringBuilder can be applied.
 * This specific example demonstrates using the simple
 * ToStringBuilder.reflectionToString(object) approach without any non-default
 * toString styles being provided and without any fields that should not be
 * part of the toString() being specified.
 * 
 * @author Dustin
 */
public class Parent
{
   /** String member that is private. */
   private String parentString = "Hello Mars!";

   /** Primitive (int) member that is private. */
   private int parentInt = 12;

   /** Enum (since JDK 1.5) type. */
   protected enum FruitEnum
   {
      APPLE,
      BANANA,
      MANGO,
      ORANGE,
      PINEAPPLE,
      WATERMELON
   };

   /** Enum member. */
   protected FruitEnum fruit = FruitEnum.MANGO;

   /** Array (of Enums) member. */
   protected FruitEnum[] fruits = { FruitEnum.APPLE, FruitEnum.PINEAPPLE };

   /** Null Array. */
   protected String[] nullArray = null;

   /** List (of Enums) member. */
   protected List<FruitEnum> fruitsList = new ArrayList<FruitEnum>();

   /** Null List. */
   protected List<String> nullList = null;

   /** Map (of Enums) member. */
   protected Map<FruitEnum,String> fruitsMap =
      new EnumMap<FruitEnum,String>(FruitEnum.class);

   /** Null value for data member. */
   protected String nullString = null;

   /** Transient data member. */
   protected transient String transientString = "Transient!";

   /** Static data member. */
   protected static int staticCount = 0;

   /** No-arguments constructor. */
   public Parent()
   {
      fruitsList.add(FruitEnum.BANANA);
      fruitsList.add(FruitEnum.ORANGE);

      fruitsMap.put(FruitEnum.APPLE, "One a day keeps the doctor away.");
      fruitsMap.put(FruitEnum.MANGO, "Paulie really likes these.");
      fruitsMap.put(FruitEnum.PINEAPPLE,
         "Crossbreeding of an apple tree and a pine tree?");
   }

   /**
    * The most important method of this class because this entire example is on
    * ToStringBuilder.
    * 
    * @return The String representation of this class as constructed via
    *    reflection by Apache Commons ToStringBuilder.
    */
   @Override
   public String toString()
   {
      return ToStringBuilder.reflectionToString(this);
   }
}


The output of this class's toString method is shown next:


PARENT:
dustin.examples.common.Parent@10b30a7[parentString=Hello Mars!,parentInt=12,fruit=MANGO,fruits={APPLE,PINEAPPLE},nullArray=<null>,fruitsList=[BANANA, ORANGE],nullList=<null>,fruitsMap={APPLE=One a day keeps the doctor away., MANGO=Paulie really likes these., PINEAPPLE=Crossbreeding of an apple tree and a pine tree?},nullString=<null>]

The generated output demonstrates how easy it was, with one line of code, to represent much of the object's state via its toString() method. The generated output includes handling of an array, a List, Map, and even a null value. The example also demonstrates that the default setting of ToStringBuilder does not include statics or transients.

ReflectionChild.java

This class extends the Parent class shown above. This example will demonstrate ToStringBuilder's handling of inherited data, including of the parent class's private data.

package dustin.examples.common;

import org.apache.commons.lang.builder.ToStringBuilder;

/**
 * This class demonstrates Apache Commons ToStringBuilder behavior in an
 * inheritance/extends relationship.
 * 
 * @author Dustin
 */
public class ReflectionChild extends Parent
{
   private String childString = "Hello Jupiter!";

   /** No-arguments constructor. */
   public ReflectionChild() {}

   /**
    * Demonstrating automatically generated (via reflection) toString() of a
    * child class using ToStringBuilder (Apache Commons).
    * 
    * @return String constructed from this object via reflection by the Apache
    *    Commons ToStringBuilder class.
    */
   @Override
   public String toString()
   {
      return ToStringBuilder.reflectionToString(this);
   }
}

As with the Parent.toString() implementation, this implementation uses the simple, default ToStringBuilder.reflectionToString method on itself (this). The output from running this class's toString() is shown next:


CHILD/REFLECTION:
dustin.examples.common.ReflectionChild@66848c[childString=Hello Jupiter!,parentString=Hello Mars!,parentInt=12,fruit=MANGO,fruits={APPLE,PINEAPPLE},nullArray=<null>,fruitsList=[BANANA, ORANGE],nullList=<null>,fruitsMap={APPLE=One a day keeps the doctor away., MANGO=Paulie really likes these., PINEAPPLE=Crossbreeding of an apple tree and a pine tree?},nullString=<null>]

One of the most interesting aspects of this child's toString() output is that even the parent's private data members (privateInt and privateString) are included in the ToStringBuilder-generated String. It is convenient that the child class, with the same single line of code, can provide a String representation of its content (including what it inherits from its parent).

ReflectionChildExcludes.java

There are times when we don't want every member to be included in the generated String representation of the object contents. As shown above, one way to prevent this is to make the data member static or transient. However, it is not really a good idea to make a data member transient or static simply for its toString() implementation. Fortunately, the ReflectionToStringBuilder class (extends ToStringBuilder) provides an easy mechanism for excluding fields that you don't want included in the toString() generation. In this case, I am not comfortable having a child class display its parent's private data as though it was the child's data. I can exclude a private element (or any other desired field) with the ReflectionToStringBuilder.setExcludeFieldNames method. In this case, I'll exclude the parent's two private data members (privateInt and privateString) and a data member from this same class (ignoreString) that I don't want included in the String representation.

This example takes ReflectionToStringBuilder even further than simply excluding certain fields from the generated String representation. The example also uses other methods on ReflectionToStringBuilder to specify that static members should be included and that transient members should be included.

1 2 Page 1
Page 1 of 2