// Copyright (c) 2004 Dustin Sallings <dustin@spy.net>
package net.spy.util;
import java.lang.reflect.Field;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.Map;
import java.util.Set;
import net.spy.SpyObject;
import net.spy.log.Logger;
/**
* Dump an object and all of its contents.
*/
public class ObjectDump extends SpyObject {
private final Logger logger;
/**
* Get an instance of ObjectDump.
*/
public ObjectDump() {
super();
logger=getLogger();
}
// Get all of the fields available to this class or any of its super
// classes.
private void getAllFields(Class<?> c, Set<Field> s) throws Exception {
Field[] fields=c.getDeclaredFields();
for(Field field : fields) {
field.setAccessible(true);
s.add(field);
}
if(c.getSuperclass() != null) {
getAllFields(c.getSuperclass(), s);
}
}
/**
* Report that the given object is being examined.
*
* @param path the path to the object
* @param o the object
*/
protected void reportExamining(String path, Object o) {
logger.info("Examining %s - %s - %s", path, o.getClass(), o);
}
/**
* Report a primitive was found.
*
* @param path the path to the primitive
* @param v the value of the primitive
*/
protected void reportPrimitive(String path, Object v) {
logger.info("Primitive value for %s is %s", path, v);
}
/**
* Report a path's value is null.
*
* @param path the path
*/
protected void reportNull(String path) {
logger.info(path + " is null");
}
/**
* Report a duplicate object at the given path.
*
* @param path the path of the duplicate
* @param prevPath the first seen path of this object
* @param o the object itself
*/
protected void reportDuplicate(String path, String prevPath, Object o) {
logger.info("Saw duplicate %s instance at %s previously seen at %s",
o.getClass(), path, prevPath);
}
/**
* Report an exception traversing an object.
*
* @param path the path of the object
* @param o the object
* @param e the exception that occurred
*/
protected void reportException(String path, Object o, Exception e) {
logger.info("Problem reading %s at %s - %s", o.getClass(), path, o, e);
}
// Dump this object
private void dumpObject(Object o, String path, int depth,
Map<Object, String> seen) {
try {
if(!seen.containsKey(o)) {
seen.put(o, path);
Class<? extends Object> c=o.getClass();
reportExamining(path, o);
Set<Field> fields=new HashSet<Field>();
getAllFields(c, fields);
for(Field field : fields) {
Class<?> fieldType=field.getType();
String fieldName=field.getName();
String thisPath=path + "." + fieldName;
if(fieldType.isPrimitive()) {
reportPrimitive(thisPath, field.get(o));
} else {
Object fieldValue=field.get(o);
if(fieldValue == null) {
reportNull(thisPath);
} else {
dumpObject(fieldValue, thisPath, depth+1, seen);
}
}
}
} else {
reportDuplicate(path, seen.get(o), o);
}
} catch(Exception e) {
reportException(path, o, e);
}
}
/**
* Dump the given object.
*/
public void dumpObject(Object o) {
if(o == null) {
throw new NullPointerException("Cannot dump a null object.");
}
dumpObject(o, "o", 0, new IdentityHashMap<Object, String>());
}
}