Sometimes for debugging I want to dump an object recursively. That is, I'd like to see not just an Apache Commons Lang-style toString
, but a recursive version which descends fields to display their inner bits as well.
Rather than complain, I coded my own. Enjoy!
public static String recursiveToString(final Object o) { final StringBuilder buffer = new StringBuilder(); recursiveToString(new StringBuilder(), o, buffer, new HashSet<Object>()); return buffer.toString(); } private static void recursiveToString(final StringBuilder prefix, final Object o, final StringBuilder buffer, final Set<Object> seen) { if (null == o) { buffer.append("null\n"); return; } // Mark back references with angle brackets if (seen.contains(o)) { buffer.append('<'); objectToString(o, buffer); buffer.append(">\n"); return; } seen.add(o); objectToString(o, buffer); // TODO: More clever to see if protection domain is in the JDK if (shouldNotRecurse(o, o.getClass().getPackage().getName())) { buffer.append('='); buffer.append(o); buffer.append('\n'); return; } buffer.append("={"); buffer.append('\n'); final StringBuilder fieldPrefix = new StringBuilder(prefix); fieldPrefix.append(" "); for (final Field field : o.getClass().getDeclaredFields()) { field.setAccessible(true); buffer.append(fieldPrefix); buffer.append(field.getName()); buffer.append('('); buffer.append(Modifier.toString(field.getModifiers())); buffer.append(")="); try { recursiveToString(fieldPrefix, field.get(o), buffer, seen); } catch (final IllegalAccessException e) { buffer.append("? ("); buffer.append(e.getMessage()); buffer.append(')'); } } buffer.append(prefix); buffer.append("}\n"); } private static boolean shouldNotRecurse(final Object o, final String packageName) { try { return (packageName.startsWith("java.") || packageName .startsWith("javax.")) && !Object.class .getMethod("toString") .equals(o.getClass().getMethod("toString")); } catch (NoSuchMethodException e) { throw new RuntimeException(e); } } private static void objectToString(final Object o, final StringBuilder buffer) { buffer.append(o.getClass().getName()); buffer.append('@'); buffer.append(Integer.toHexString(System.identityHashCode(o))); }
7 comments:
Less "final". 8^)
Thanks, Paul. I normally strip them from code I post to the blog, but forgot this time.
If it makes you happier, mentally substitute the word 'immutable' or 'const'.
Nice one. Thank you.
Very useful, thanks!
How to avoid circular reference error?
Getting this error-
Exception in thread "main" java.lang.StackOverflowError
To avoid circular references for every object processes check for the existence of the object id in a set that you created, if the object isn't there, add it and process. If it's already there move to the next object.
In hindsight Anonymous is right about keeping track of what I've seen.
Post a Comment