Generating ToString in Java Consistently

Contents


The Problem

One clumsy, but necessary boilerplate when doing Java coding is generating the toString() methods for the classes in your application. This becomes more complex if the object-hierarchy in your codebase has more depth: you will need to generate the parent's toString() and then generate the children's toString. This operation, is complicated because of immutability of String: if the parent class encloses the information inside a {...}, the child class cannot directly utilize the toString of parent (without compromising the beauty of toString output).

Solution: My approach

I wanted a simple solution for this problem without reverting to reflection. The solution designed is now available in the WizTools.org Commons Lib project.

ToString Interface

The primary interface is the ToString interface. So any class that needs to utilize this framework needs to comply to this contract. This interface defines one method:

ToStringBuilder getToStringBuilder();

ToStringBuilder

ToStringBuilder is the builder class which will be used for building the toString() output. There are three public methods that can be called:

public ToStringBuilder append(Object obj);
public ToStringBuilder append(String name, Object obj);
public String toString();

As you would have guessed, the append methods are for internally storing the object representation for generating the final toString() output.

Using

I will explain the usage by an example. The example is from the test class.

Let us take the example of a simple hierarchy: a Parent class and a Child class:

    class Parent implements ToString {
        private String name = "Parent Name";
        
        @Override
        public ToStringBuilder getToStringBuilder() {
            ToStringBuilder toStringBuilder = new ToStringBuilder();
            toStringBuilder.append(name);
            return toStringBuilder;
        }
        
        @Override
        public final String toString() { // make it final!
            return getToStringBuilder().toString();
        }
    }
    
    class Child extends Parent {
        private String age = "From Child Age";

        @Override
        public ToStringBuilder getToStringBuilder() {
            return super.getToStringBuilder().append(age);
        }
    }

Things to note:

  1. The Parent class implements ToString.
  2. The Parent's toString() method is final.
  3. The Parent's toString() calls the toString() of the ToStringBuilder.
  4. The Child class overrides the getToStringBuilder(), but invokes the parent's method and appends the child details.

The output:

        Parent p = new Parent();
        String result = p.toString();
        String expResult = "{Parent Name}";
        assertEquals(expResult, result);
        Child c = new Child();
        String result = c.toString();
        String expResult = "{Parent Name; From Child Age}";
        assertEquals(expResult, result);

Conclusion

This framework tries to minimize the boiler-plate code required to consistently generate toString() output. But, in my experience of designing APIs, this is not the most beautiful solution. The implementation leaves many tasks to be implemented by the user of the API, and also fails in not providing a definitive contract. But this is the simplest and most usable I was able to think of.

Alternative: Commons ToStringBuilder

The kitchen-sink of ToString framework is available in the Commons Lang library:

http://commons.apache.org/lang/api-2.4/org/apache/commons/lang/builder/ToStringBuilder.html

Posted on April 15, 2012 12:04 PM by Subhash Chandran
java
blog comments powered by Disqus