8

How do I print the content of an object recursively?

tom
  • 4,911
  • 11
  • 37
  • 39

9 Answers9

12

You can print it recursively by overriding toString in all your classes.

If you want to have a method like printObjectRecursively(Object o) you need to dive into reflection, fetch the fields, print their name and content recursively using printObjectRecursively(someField).

Example:

public class Test {
    public static void main(String[] args) {
        A a = new A();
        System.out.println(a);
    }
}

class A {
    int i = 5;
    B obj = new B();
    String str = "hello";
    public String toString() {
        return String.format("A: [i: %d, obj: %s, str: %s]", i, obj, str);
    }
}

class B {
    int j = 17;
    public String toString() {
        return String.format("B: [j: %d]", j);
    }
}

Prints:

A: [i: 5, obj: B: [j: 17], str: hello]

A reflection-based recursive print method could be written something like this

private static final List LEAVES = Arrays.asList(
        Boolean.class, Character.class, Byte.class, Short.class,
        Integer.class, Long.class, Float.class, Double.class, Void.class,
        String.class);

public static String toStringRecursive(Object o) throws Exception {

    if (o == null)
        return "null";

    if (LEAVES.contains(o.getClass()))
        return o.toString();

    StringBuilder sb = new StringBuilder();
    sb.append(o.getClass().getSimpleName()).append(": [");
    for (Field f : o.getClass().getDeclaredFields()) {
        if (Modifier.isStatic(f.getModifiers()))
            continue;
        f.setAccessible(true);
        sb.append(f.getName()).append(": ");
        sb.append(toStringRecursive(f.get(o))).append(" ");
    }
    sb.append("]");
    return sb.toString();
}
aioobe
  • 413,195
  • 112
  • 811
  • 826
  • 1
    This method gave me a stackoverflowError :) – jumps4fun May 31 '16 at 14:19
  • @KjetilNordin is right, recursion should be avoided when possible. A nice read about that on DZone : https://dzone.com/articles/folding-the-universe-part-ii-abstracting-recursion ("Folding the Universe" articles). – Benj Dec 01 '16 at 10:57
  • @Benj, this was presumably because KjetilNordin had a loop in his graph. Had this been done as naively in an iterative way, the program would not have terminated (or crashed due to an OOME). I think it's perfectly fine to solve this type of problem with recursion. – aioobe Dec 01 '16 at 21:27
  • @aioobe, I agree that this process should not SO on "everyday-objects", but I try to avoid recursion when I can (but it's an IMHO). I totally agree with your code for debugging purposes, you provided a clever solution for non-cyclic graphs. I'm using it since yesterday, works fine, thanks :) – Benj Dec 02 '16 at 00:36
4

You can use:

ToStringBuilder.reflectionToString(this);

Apache Common Lang contains ToStringBuilder class. You can define different style with ToStringStyle object.

y.efe
  • 51
  • 1
1

I've had great success doing this on a casual basis using XStream to dump JSON representations of objects. It recurses down objects and just seems to do what you want it to do most of the time. And it's super lightweight. Example:

private static final XStream jsonXStream = 
    new XStream(new JsonHierarchicalStreamDriver());

public static String toDebugString(Object object) {
    return jsonXStream.toXML(object);  
    // ignore "toXML" name, it's going to be JSON.
}
HenryTaylor
  • 73
  • 1
  • 4
0

You should implement the toString method for your classes - it will print the information about the class members - usually using their toString methods. |Then you jut iterate through the collection and call toString of each item

Sergii Pozharov
  • 17,366
  • 4
  • 29
  • 30
0

Do you really need print this informations out? Maybe watch during debbuging will be enough?

noisy
  • 6,495
  • 10
  • 50
  • 92
0

You are looking for something similar to PHP's var_dump, see if this question is of any help: What is the Java equivalent of PHP var_dump?

Also, have a look at reflection: http://java.sun.com/developer/technicalArticles/ALT/Reflection/

Community
  • 1
  • 1
Alberto Zaccagni
  • 30,779
  • 11
  • 72
  • 106
0

You can override the toString method.

Example:

class foo
{
 int i,j;

 String toString()
 {
 StringBuilder b=new StringBuilder();
 return b.append(i).append(j).toString();
 }
}
Emil
  • 13,577
  • 18
  • 69
  • 108
0

Use one of the serialization libraries like Jackson (JSON).

This dumps everything in plain text. If you use a Javascript capable editor to prettify the content, with a bit of luck, you might actually make some sense out of it.

If a lot of the objects are not serializable, you might end up with a lot of readable gibberish which will not help anything, unfortunately,

YMMV

Peter Tillemans
  • 34,983
  • 11
  • 83
  • 114
0

In some cases it is easy to use Gson to print object. But sometimes gson does not work.

Here I just improve aioobe' answer for this case:

  • don't print printed objects (protect from infinite cycles)
  • print collections
  • don't go deeply on few basic types, like BigInteger
    private static final Set<Object> looked = new HashSet<>();

    private static final List LEAVES = Arrays.asList(
            Boolean.class, Character.class, Byte.class, Short.class,
            Integer.class, Long.class, Float.class, Double.class, Void.class,
            String.class, java.math.BigInteger.class, java.math.BigDecimal.class);

    public static void toStringRecursive(Object o, StringBuilder sb) throws Exception {
        if (o == null) {
            sb.append("null");
            return;
        }

        if (looked.contains(o)) return;
        looked.add(o);

        if (LEAVES.contains(o.getClass())) {
            sb.append(o);
            return;
        }

        sb.append(o.getClass().getSimpleName()).append(": [");
        if (o.getClass().isArray()) {
            for (Object x : (Object[]) o) {
                toStringRecursive(x, sb);
            }
        } else if (Iterable.class.isAssignableFrom(o.getClass())) {
            for (Object x : (Iterable) o) {
                toStringRecursive(x, sb);
            }
        } else if (Map.class.isAssignableFrom(o.getClass())) {
            for (Object entry : ((Map)o).entrySet()) {
                toStringRecursive(entry, sb);
            }
        } else {
            for (Field f : o.getClass().getDeclaredFields()) {
                if (Modifier.isStatic(f.getModifiers()))
                    continue;
                f.setAccessible(true);
                sb.append(f.getName()).append(": ");
                toStringRecursive(f.get(o), sb);
                sb.append(" ");
            }
        }
        sb.append("]\n");
    }
Mikhail Ionkin
  • 568
  • 4
  • 20