Download

jar UniversalToString.jar Compiled classes
src UniversalToString-src.zip Source code

Additional Information

src Subversion repository
javadoc Javadoc
releases Old releases

Five minute tutorial

UniversalToString is a java class that prints out the internal state of an object using reflection. The UniversalToString class builds a String by recursively traversing the contents of an object and printing out the names, types, and values of all of its fields. It is loosely based on some code in Core Java 2, Volume I – Fundamentals. The simplest way to use the UniversalToString class is in the implementation of your own classes’ toString methods. Say we have a simple Person class:

public class Person {
    private final String first;
    private final String last;
    public Person(final String first, final String last) {
        this.first = first;
        this.last = last;
    }
}

Person does not implement the toString method, so when it is printed to standard out, Object.toString is used instead. The generated String contains the type name and the address in memory where the object lives. Normally this is not very useful information.

Person john = new Person("John", "Smith");
System.out.println(john);

Console output:

tostring.Person@19821f

To improve the output, we can override the toString method in the Person class.

@Override
public String toString() {
    return "Person: first [" + this.first + "] last [" + this.last + "]";
}
Person: first [John] last [Smith]

Implementing the toString method like this is tedious, repetitive, and fragile. That’s where UniversalToString comes in.

@Override
public String toString() {
    return UniversalToString.print(this);
}
Person(first=John,last=Smith)

Collections

UniversalToString has special logic for arrays, collections, and maps. This example uses a list, but the output is similar for each.

Person john = new Person("John", "Smith");
Person jane = new Person(“Jane”, “Doe”);
List list = new ArrayList();
list.add(john);
list.add(jane);
System.out.println(UniversalToString.print(list));
ArrayList{Person(first=John,last=Smith), Person(first=Jane,last=Doe)}

Custom formatting

Unfortunately our work isn’t done. The String created by UniversalToString isn’t particularly informative for certain objects. For example, let’s change the last example to print one Person and one Date:

Person john = new Person("John", "Smith");
Date date = new Date(1206552944822l);
List list = new ArrayList();
list.add(john);
list.add(date);
System.out.println(UniversalToString.print(list));
ArrayList{Person(first=John,last=Smith), Date(fastTime=1206552944822,cdate=null)}

We can customize the formatting of UniversalToString by creating an implementation of TypedToString that handles Date objects.

public class DateToString implements TypedToString {
    private final DateFormat dateFormat;
    public DateToString() {
        this.dateFormat = new SimpleDateFormat();
        this.dateFormat.setTimeZone(TimeZone.getTimeZone("America/New_York"));
    }
    public boolean handlesType(final Object object) {
        return object instanceof Date;
    }
    public String print(final Object object) {
        return this.dateFormat.format((Date) object);
    }
}

Now we just need to change the line that prints the list.

System.out.println(UniversalToString.print(list, new DateToString()));
ArrayList{Person(first=John,last=Smith), 3/26/08 1:35 PM}

The second argument to print is varargs TypedToString, so we can pass in as many special formatting rules as we need.

 
  • Guest

    I wrote a similar algorithm this year using reflection.
    At some time, i had problems concerning “looping references” where one object had a reference to another and the other had a reference back.
    As my algorithm wents up the whole object hirarchie and reads all attributes, whether private or not, the only way to solve that problem was to check the current Threads StackTrace.
    So i checked whether an object was visited more than once, and then, when it was visited the second time (in the loop) i did not call my universal toString algorithm recursive but only told the name of the attribute and not the content. So i solved that endless loop problem.
    A second problem i saw was with Collections that were not thread-safe. When my universal algorithm calls the toString-method of some collections that are being changed right now from other threads, it throws concurrency-exceptions. So in that case, a synchronized on the object and the need of synchronising the changing-side too were neccessary.

    I hope you solved these problems too, as universal toString-methods rock!
    Hope you don’t mind me choosing my own algorithm for the future, as it was hard work and works really fine now!

    • My implementation solves the problem of dealing with cycles in the graph using the identity-set called visited. You do not need to look at the call stack.

      I guess the algorithm could take a lock on every object it’s iterating over to deal with concurrency, but I think that’s going too far. Besides, it’s very deadlock prone since it’s hard to predict the order that the locks will be taken in a depth-first search algorithm like this one.