Java: how to avoid circual references when dumping object information with reflection?
- by Tom
I've modified an object dumping method to avoid circual references causing a StackOverflow error. This is what I ended up with:
//returns all fields of the given object in a string
public static String dumpFields(Object o, int callCount, ArrayList excludeList)
{
//add this object to the exclude list to avoid circual references in the future
if (excludeList == null) excludeList = new ArrayList();
excludeList.add(o);
callCount++;
StringBuffer tabs = new StringBuffer();
for (int k = 0; k < callCount; k++)
{
tabs.append("\t");
}
StringBuffer buffer = new StringBuffer();
Class oClass = o.getClass();
if (oClass.isArray()) {
buffer.append("\n");
buffer.append(tabs.toString());
buffer.append("[");
for (int i = 0; i < Array.getLength(o); i++)
{
if (i < 0) buffer.append(",");
Object value = Array.get(o, i);
if (value != null)
{
if (excludeList.contains(value))
{
buffer.append("circular reference");
}
else if (value.getClass().isPrimitive() || value.getClass() == java.lang.Long.class || value.getClass() == java.lang.String.class || value.getClass() == java.lang.Integer.class || value.getClass() == java.lang.Boolean.class)
{
buffer.append(value);
}
else
{
buffer.append(dumpFields(value, callCount, excludeList));
}
}
}
buffer.append(tabs.toString());
buffer.append("]\n");
}
else
{
buffer.append("\n");
buffer.append(tabs.toString());
buffer.append("{\n");
while (oClass != null)
{
Field[] fields = oClass.getDeclaredFields();
for (int i = 0; i < fields.length; i++)
{
if (fields[i] == null) continue;
buffer.append(tabs.toString());
fields[i].setAccessible(true);
buffer.append(fields[i].getName());
buffer.append("=");
try
{
Object value = fields[i].get(o);
if (value != null)
{
if (excludeList.contains(value))
{
buffer.append("circular reference");
}
else if ((value.getClass().isPrimitive()) || (value.getClass() == java.lang.Long.class) || (value.getClass() == java.lang.String.class) || (value.getClass() == java.lang.Integer.class) || (value.getClass() == java.lang.Boolean.class))
{
buffer.append(value);
}
else
{
buffer.append(dumpFields(value, callCount, excludeList));
}
}
}
catch (IllegalAccessException e)
{
System.out.println("IllegalAccessException: " + e.getMessage());
}
buffer.append("\n");
}
oClass = oClass.getSuperclass();
}
buffer.append(tabs.toString());
buffer.append("}\n");
}
return buffer.toString();
}
The method is initially called like this:
System.out.println(dumpFields(obj, 0, null);
So, basically I added an excludeList which contains all the previousely checked objects. Now, if an object contains another object and that object links back to the original object, it should not follow that object further down the chain.
However, my logic seems to have a flaw as I still get stuck in an infinite loop. Does anyone know why this is happening?