You could use reflection to find methods that return collections and iterate through the elements recursively:
CollectionNavigator.navigate(rootObject);
Code:
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
public class CollectionNavigator {
private Set<Collection<?>> visitedCollections = new HashSet<Collection<?>>();
public static void navigate(Object object) {
CollectionNavigator navigator = new CollectionNavigator();
navigator.navigateObject(object);
}
public void navigateObject(Object object) {
if (object == null) {
return;
}
Method[] methods = object.getClass().getMethods();
for (int i=0; i<methods.length; i++) {
if (methodReturnsCollection(methods[i])) {
try {
Collection<?> collection = (Collection<?>)methods[i].invoke(object);
navigateCollection(collection);
} catch (IllegalArgumentException e) {
throwRuntimeException(methods[i], e);
} catch (IllegalAccessException e) {
throwRuntimeException(methods[i], e);
} catch (InvocationTargetException e) {
throwRuntimeException(methods[i], e);
}
}
}
}
private void navigateCollection(Collection<?> collection) {
if (collection == null) {
return;
}
if (visitedCollections.contains(collection)) {
// avoid recursive references in collections
return;
}
visitedCollections.add(collection);
for (Object object : collection) {
navigateObject(object);
}
}
private boolean methodReturnsCollection(Method method) {
Class<?> methodReturnType = method.getReturnType();
Class<?>[] interfaces = methodReturnType.getInterfaces();
for (int i=0; i<interfaces.length; i++) {
if (interfaces[i].equals(Collection.class)) {
return true;
}
}
return false;
}
private void throwRuntimeException(Method method, Exception e) {
throw new RuntimeException("CollectionNavigator failed to invoke method: "+method.getName(), e);
}
}